反射
是什么
加载类,并允许以编程的方式解剖列中的各种成分(成员变量、方法、构造器等)
反射学什么
-
反射第一步:加载类,获取类的字节码:Class对象
Student.java -> 编译成Student.class -> 解析成 字节码文件 -> 加载到内存中去
-
获取类的构造器:Constructor对象
-
获取类的成员变量:Field对象
-
获取类的成员方法:Method对象
获取Class对象
获取Class对象有三种方式:
Class c1 = 类名.class
- 调用Class提供方法:
public static Class forName(String package)
- Object提供的方法:
public Class getClass(); Class c3 = 对象.getClass();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
// 方式1:类名.class
Class c1 = Student.class;
System.out.println(c1); // class cn.snailsir.reflect.Student cn.snailsir.reflect包下的Student类
// 方式2:Class.forName(全类名)
// public static Class forName(String package)
Class c2 = Class.forName("cn.snailsir.reflect.Student");
System.out.println(c2); // class cn.snailsir.reflect.Student
// 方式3:对象.getClass()
// public Class getClass();
Student s1 = new Student();
Class c3 = s1.getClass();
System.out.println(c3); // class cn.snailsir.reflect.Student
System.out.println(c1 == c2);// true
System.out.println(c2 == c3);// true
|
获取类构造器
Class提供了从类中获取构造器的方法
获取类构造器作用
返回初始化对象
常用方法
方法 |
说明 |
Constructor>[] getConstructors() |
获取全部构造器(只能获取public修饰的) |
Constructor>[] getDeclaredConstructors() |
获取全部构造器(只要存在就能拿到) |
Constructor<T> getConstructor(Class>… parameterTypes) |
获取某个构造器(只要获取public修饰的) |
Constructor<T> getDeclaredConstructor(Class>… parameterTypes) |
获取全部构造器(只要存在就能拿到) |
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
@Test
public void testGetCOnstructors(){
// 获取类的Class对象
Class c = Cat.class;
// 获取类的全部构造器
// Constructor[] constructors = c.getConstructors();
Constructor[] constructors = c.getDeclaredConstructors();
// 遍历构造器
for(COnstructor con:constructors){
System.out.println(con.getName() + "==>" + con.getParameterCount());
}
}
@Test
public void testGetCOnstructor() throws Exception{
// 获取类的Class对象
Class c = Cat.class;
// 获取类的某个构造器:无参构造器
// Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
Constructor con1 = c.getDeclaredConstructor();// 定位无参构造器
Constructor con2 = c.getDeclaredConstructor(String.class,int.class); // 定位有参构造器
// 遍历构造器
for(COnstructor con:constructors){
System.out.println(con.getName() + "==>" + con.getParameterCount());
}
// 初始化对象
// T newInstance(Object... initargs)
Cat c1 = (Cat) con1.newInstance();
System.out.println(c1);
con2.setAccessible(true); // 禁止检查访问权限(暴力反射)
Cat c2 = (Cat) con2.newInstance("叮当猫",30); // 如果con2.setAccessible(true)不加,私有的有参构造器则无法初始化,加上了,则可以初始化
System.out.println(c2);
}
|
获取类的成员变量
Class提供了从类中获取成员变量的方法
获取类成员变量作用
依然是赋值、取值
常用方法
方法 |
说明 |
Public Field[] getFields() |
获取类的全部成员变量(只能获取public修饰的) |
Public Field[] getDeclaredFields() |
获取类的全部成员变量(只要存在就能拿到) |
Public Field getField(String name) |
获取类的某个成员变量(只要获取public修饰的) |
Public Field getDeclaredField(String name) |
获取类的某个成员变量(只要存在就能拿到) |
方法 |
说明 |
void set(Object obj,Object value) |
赋值 |
Object get(Object obj) |
取值 |
public void setAccessible(boolean flag) |
设置为true,表示禁止检查访问控制(暴力反射) |
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
Class c = Cat.class;
// 获取类的全部成员变量
// Public Field[] getDeclaredFields()
Field[] fields = c.getDeclaredFields();
for(Field field:fields){
System.out.println(field.getType()+"==>"+field.getName());
}
// 定位某个成员变量
Field fname = c.getDeclaredField("name");
// 取值
Cat cat = new Cat();
fname.setAccessible(true);// 暴力反射
fname.set(cat,"多啦A梦");
String name = (String)fname.get(cat);
System.out.println(name);
|
获取类的成员方法
Class提供了从类中获取成员方法的API
获取类成员变量作用
依然是执行
常用方法
方法 |
说明 |
Method[] getMethods() |
获取类的全部成员方法(只能获取public修饰的) |
Method[] getDeclaredMethods() |
获取类的全部成员方法(只要存在就能拿到) |
Method getMethod(String name,Class>… parameterTypes) |
获取类的某个成员方法(只要获取public修饰的) |
Method getDeclaredMethod(String name,Class>… parameterTypes) |
获取类的某个成员方法(只要存在就能拿到) |
Method提供的方法 |
说明 |
public Object invoke(Object obj,Object… args) |
触发某个对象的该方法执行 |
public void setAccessible(boolean flag) |
设置为true,表示禁止检查访问控制(暴力反射) |
案例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
Class c = Cat.class;
// 获取类的全部成员方法
Method[] methods = c.getDeclaredMethods();
for(Method method:methods){
System.out.println(method.getName()+" "+method.getParameterCount());
}
// 定位单个方法
Method eat1 = c.getDeclaredMethod("eat");
Method eat2 = c.getDeclaredMethod("eat",String.class);
// 定位方法的目的:依然是执行它
Cat cat = new Cat();
Object result = eat1.invoke(cat); // 无参
eat2.setAccessible(true);
Object result2 = eat2.invoke(cat,"鱼儿"); // 有参
System.out.println(result2);
|
作用
基本作用:可以得到一个类的全部成分然后进行操作(Idea提示)
可以破坏封装性
最重要的用途:适合做java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能