0%

Java-反射

反射


动态语言

程序运行时,可以改变程序结构或变量类型。典型的有Python、ruby、javascript等,如:

1
2
3
4
function test(){
var s = "var a=3;var b=5;alert(a+b);"
eval(s);
}

C,C++,Java不是动态语言,但JAVA有一定的动态性,可以利用反射机制、字节码操作获得类似动态语言的特性。

反射机制

指的是可以在运行时加载、探知、使用编译期间完全未知的类。

程序在运行状态中,可以动态加载一个只有名称的类,对于任意一个已加载的类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能调用它的任意一个方法和属性;

加载完类之后,在堆内存中,就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以被形象的称为反射(reflection)

Class类介绍

java.lang.Class类十分特殊,用来表示java中类型本身

Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个Class对象。

当一个class被加载,或当加载器(class loader)的defineClass()被Jvm调用时,JVM便自动产生Class对象

Class类是Reflection的根源,针对任何想动态加载、运行的类,唯有先获得相应的Class对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//获取类的名字
System.out.println(c.getName());//获得包名+类名
System.out.println(c.getSimpleName());//获得类名

//获取属性信息
Field[] field = c.getFields();//只能获得public修饰的field
Field[] fields = c.getDeclaredFields();//获得所有的field
Field f= c.getField("name");

//获取方法信息
Method[] method = c.getMethods();
Method[] methods = c.getDeclaredMethods();
Method me = c.getMethod("getName",null);
Method m = c.getMethod("setName()",String.class);//如果方法有参,则必须传递参数类型对应的class对象

//获取构造器信息
Constructor[] constructor = c.getConstructors();
Constructor[] constructors = c.getDeclaredConstructors();
Constructor co = c.getConstructor(null);//传递参数类型
Constructor cos = c.getDeclaredConstructor(String.class,int.class);

动态操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//通过反射API调用构造方法,构造对象
String str = (String) c.newInstance();//其实是调用了String的无参构造方法
System.out.println(str);

Constructor co = c.getConstructor(String.class);
String s = (String) co.newInstance("hello");
System.out.println(s);

//通过反射API调用普通方法
String s2 = (String) c.newInstance();
Method m = c.getMethod("length",null);

System.out.println(m.invoke(s2));//invoke激活函数

//通过反射API操作属性
Field f = c.getDeclaredField("hash");
f.setAccessible(true);//这个属性不需要安全检查,可以直接访问
f.set(s2,12345); //通过反射直接写属性
System.out.println(s2.hashCode());