
反射机制是动态语言的关键,可以在程序运行期间获得任何类的内部信息,并能直接操作任意对象的内部属性及方法。通俗的说就是在运行时代码可以根据某些条件改变自身结构。
主要动态语言:Javascript,PHP,Python
静态语言:Java,C,C++
Java不是动态语言,但Java可以称之为 “准动态语言” 。即Java有一定的动态性,我们可以利用反射机制,字节码操作获得类似动态语言的特性。
程序经过Javac.exe命令后,会生成一个或多个字节码文件(.class结尾)。(编译过程)
接着我们使用Java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程称为类的加载。加载到内存中的类,我们称之为运行时类,此运行时类,就作为Class的一个实例.(运行时的类同样也可以作为一个对象,体现出了Java万事万物皆对象的思想)
public class newclass {
//获取class实例的方式(掌握前三种方式)
@Test
public void test01() throws ClassNotFoundException {
//方式一:调用运行时类的属性:.class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p = new Person();
Class clazz2 = p.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:forName(String classPath) 常用
Class clazz3 = Class.forName("newday.wangluobiancheng.Person");//抛异常
System.out.println(clazz3);
//方式四:使用类的加载器:Classloader
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("newday.wangluobiancheng.Person");
System.out.println(clazz4);
}
}
注意;
使用newInstance()创建对应的运行时类的对象。
@Test
public void test01() throws IllegalAccessException, InstantiationException {
Class personClass = Person.class;
Person person = personClass.newInstance();
}
注意;
@Test
public void test(){
Class aClass = Person.class;
//获取属性结构
//getFields():获取当前运行时类及其父类声明为public访问权限的属性
Field[] fields = aClass.getFields();
for(Field f:fields){
System.out.println(f);
//输出结果
//public java.lang.String newday.wangluobiancheng.Person.name
//public int newday.wangluobiancheng.Person.age
}
}
| Field[ ] getFields( ) | 获取当前运行时类及其父类中声明为public的属性,并返回数组 |
| Field[ ] getDeclaredFields( ) | 获取当前运行时类的所有属性,包括私有权限的属性。(不包括父类中的属性) |
@Test
public void test(){
Class aClass = Person.class;
//获取属性结构
//getFields():获取当前运行时类及其父类声明为public访问权限的属性
Field[] fields = aClass.getFields();
for(Field f:fields){
//获取当前属性的权限
int modifier = f.getModifiers();
System.out.println(Modifier.toString(modifier));
//获取数据类型
Class type = f.getType();
System.out.println(type);
//获取变量名
String name = f.getName();
System.out.println(name);
}
}
4. 获取运行时类的方法及内部结构
//获取运行时类及其父类的public方法
Method[] methods = clazz.getMethods();
for(Method m:methods){
System.out.println(m);
}
//获取运行时类的所有方法
Method[] methods1 = clazz.getDeclaredMethods();
for (Method m:methods){
System.out.println(m);
//获取注解
Annotation[] a = m.getAnnotations();
for(Annotation an:a){
System.out.println(an);
}
//权限修饰符
System.out.println(Modifier.toString(m.getModifiers()));
//返回值类型
System.out.println(m.getReturnType().getName());
//方法名
System.out.println(m.getName());
//形参列表
Class[] parameterTypes = m.getParameterTypes();
if(!(parameterTypes == null && parameterTypes.length ==0)){
for (Class p:parameterTypes){
System.out.println(p.getName());//此处获取的是形参类型,无法获取形参名。
}
}
//抛出的异常
Class[] exceptionTypes = m.getExceptionTypes();
if (!(exceptionTypes == null && exceptionTypes.length ==0)){
System.out.println("throws");
for(Class ex:exceptionTypes) {
System.out.println(ex.getName());
}
}
}
}
5. 获取运行时类的构造器
@Test
public void test() {
Class clazz = Person.class;
//获取当前运行时类的public的构造器
Constructor[] constructors = clazz.getConstructors();
for(Constructor con : constructors){
System.out.println(con);
}
//获取当前运行时类的所有构造器
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
for(Constructor con : declaredConstructors){
System.out.println(con);
}
}
6. 获取运行时类的父类及其泛型
@Test
public void test66(){
Class aClass = Person.class;
//获取运行时类的父类
Class superclass = aClass.getSuperclass();
System.out.println(superclass);
//获取运行时类带泛型的父类
Type genericSuperclass = aClass.getGenericSuperclass();
System.out.println(genericSuperclass);
//获取运行时类带泛型的父类的泛型
Type genericSuperclass1 = aClass.getGenericSuperclass();
ParameterizedType pararmeterizedType = (ParameterizedType) genericSuperclass1;
Type[] actualTypeArguments = pararmeterizedType.getActualTypeArguments();
System.out.println(actualTypeArguments[0].getTypeName());
}
7. 获取运行时类实现的接口
@Test
public void test89(){
//获取运行时类的接口
Class personClass = Person.class;
Class[] interfaces = personClass.getInterfaces();
for(Class inter:interfaces){
System.out.println(inter);
}
//获取运行时类所在的包
Package aPackage = personClass.getPackage();
System.out.println(aPackage);
//获取运行时类的注解
Annotation[] annotations = personClass.getAnnotations();
for (Annotation ann:annotations){
System.out.println(ann);
}
}
@Test
public void mytools() throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class aClass = Person.class;
Object per = aClass.newInstance();
//获取指定属性:运行时类的属性声明为public(不常用)
Field age = aClass.getField("age");
//设置参数 set(指定对象,属性值)
age.set(per,100);
//获取指定对象的属性值
int age1 = (int)age.get(per);
Class personClass = Person.class;
Object pers = personClass.newInstance();
Field age2 = personClass.getDeclaredField("age");
//保证当前属性是可访问的。
age2.setAccessible(true);
age2.set(pers,10025);
int myAge = (int)age2.get(pers);
}
2. 操作指定方法
@Test
//操作非静态的方法
public void mytest() throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class clazz = Person.class;
Object p = clazz.newInstance();
//获取指定方法 getDeclaredMethod(“指定的方法”,形参类型.class)
Method show = clazz.getDeclaredMethod("show", String.class);
//保证当前方法的可访问性
show.setAccessible(true);
//调用指定方法,invoke(对应的实例,实参),invoke()的返回值即为对应方法的返回值,无返回值时返回null
Object invoke = show.invoke(p, "myfavorite");
//操作静态方法
Method showmoney = clazz.getDeclaredMethod("showmoney", String.class);
showmoney.setAccessible(true);
Object invoke1 = showmoney.invoke(Person.class);
}
3. 调用指定构造器
@Test
//获取指定构造器
public void testconstructer() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class clazz = Person.class;
Constructor declaredConstructor = clazz.getDeclaredConstructor(String.class);
declaredConstructor.setAccessible(true);
Person jack = (Person)declaredConstructor.newInstance("jack");
System.out.println(jack);
}