反射
作用:
把一个对象的成员变量、构造方法、成员函数(方法)转换为对象,然后进行动态调用。反射是框架设计的“灵魂”技术!
注意:
代码对象从创建到产生结果的过程中,要经历过编译,加载,运行,三个阶段。
编译:将 .Java 文件转换为字节码 .class 文件。(此时代码还存在于硬盘中)
加载:将 .class 文件加载到内存中,以便编辑器进行操作。
运行:使内存中的代码产生结果。
类加载器:
加载:
指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。
类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。
通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源。
- 从本地文件系统加载class文件。
- 从JAR包加载class文件。
- 通过网络加载class文件。
把一个Java源文件动态编译,并执行加载。
类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。
作用:
- 将硬盘上的Class文件加载到内存(方法区)以便后续的操作。
- 类加载器加载完成后会在堆区创建一个class对象,用来表示加载的“类结构”。
反射的第一步:获取到堆中的class对象
方法:
- Class.forName (全限定类名) 获取Class对象(然后cls.newInstance() 获取实例化对象),这种一般配合配置文件使用
- 类名.Class 获取响应类型的class对象,常用于参数列表用于传参
- 对象名.getClass() 用于方法内部,用于确定传入参数的具体类型
代码案例:
1 package com.reflex.bean;
2
3 public class Person {
4 private String Id;
5 public String name;
6 public String age;
7 protected String gender;
8
9 public String getId() {
10 return Id;
11 }
12
13 public String getName() {
14 return name;
15 }
16
17 public String getAge() {
18 return age;
19 }
20
21 public String getGender() {
22 return gender;
23 }
24
25 public void setId(String id) {
26
27 Id = id;
28 }
29
30 public void setName(String name) {
31 this.name = name;
32 }
33
34 public void setAge(String age) {
35 this.age = age;
36 }
37
38 public void setGender(String gender) {
39 this.gender = gender;
40 }
41
42 public Person(String id, String name, String age, String gender) {
43
44 Id = id;
45 this.name = name;
46 this.age = age;
47 this.gender = gender;
48 }
49
50 public Person() {
51
52 }
53
54 private void reflexDemo() {
55 System.out.println("this is a test!");
56 }
57
58 @Override
59 public String toString() {
60 return "Person{" +
61 "Id='" + Id + '\'' +
62 ", name='" + name + '\'' +
63 ", age='" + age + '\'' +
64 ", gender='" + gender + '\'' +
65 '}';
66 }
67 private void eat(){
68 System.out.println("eat food!");
69 }
70 }
1 package com.reflex.demo;
2
3 import com.reflex.bean.Person;
4
5 public class demo1 {
6 public static void main(String[] args) throws Exception {
7 // 1、 Class.forName (全限定类名) 获取Class对象(然后cls.newInstance() 获取实例化对象),这种一般配合配置文件使用
8 Class cls1 = Class.forName("com.reflex.bean.Person");
9 // 2、 类名.Class 获取响应类型的clszz 对象,常用于参数列表用于传参
10 Class<Person> cls2 = Person.class;
11 // 3、 对象名.getClass() 用于方法内部,用于确定传入参数的具体类型
12 Person person = new Person();
13 Class cls3 = person.getClass();
14 System.out.println(cls1);
15 System.out.println(cls2);
16 System.out.println(cls3);
17 System.out.println(cls1 == cls2);
18 System.out.println(cls2 == cls3);
19 System.out.println(cls1 == cls3);
20 System.out.println(cls1.getName());
21 System.out.println(cls1.getClassLoader());
22 }
23 }
cls1 == cls2 == cls3 说明:无论通过这三种方法的哪一种方法,获取的Class对象有且只有一个!(class对象只创建一次)
反射的第二步:通过Class对象获取对应的构造函数、成员变量、成员方法对象
常用方法:
- Field getField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定公共成员字段。
- Field[] getFields() 返回一个包含 Field对象的数组, Field对象反映由该 Class对象表示的类或接口的所有可访问的公共字段。
- Field getDeclaredField(String name) 返回一个 Field对象,该对象反映由该 Class对象表示的类或接口的指定声明字段。
- Field[] getDeclaredFields() 返回一个 Field对象的数组,反映了由该 Class对象表示的类或接口声明的所有字段。
- Method getMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,该对象反映由该 Class对象表示的类或接口的指定公共成员方法。
- Method[] getMethods() 返回一个包含 方法对象的数组, 方法对象反映由该 Class对象表示的类或接口的所有公共方法,包括由类或接口声明的对象以及从超类和超级接口继承的类。
- Method getDeclaredMethod(String name, Class<?>... parameterTypes) 返回一个 方法对象,它反映此表示的类或接口的指定声明的方法 Class对象。
- Method[] getDeclaredMethods() 返回一个包含 方法对象的数组, 方法对象反映由 Class对象表示的类或接口的所有声明方法,包括public,protected,default(package)访问和私有方法,但不包括继承方法。
- Constructor<T> getConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。
- Constructor<?>[] getConstructors() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。
- Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 返回一个 Constructor对象,该对象反映由此 Class对象表示的类或接口的指定构造函数。
- Constructor<?>[] getDeclaredConstructors() 返回反映由该 Class对象表示的类声明的所有构造函数的 Constructor对象的数组。
注意:可获取到public修饰的方法和属性(public),getDeclareXXX获取到对象中所有修饰符修饰的方法和属性(public,protect,private)。
代码案例:
1 package com.reflex.demo;
2
3 import java.lang.reflect.Constructor;
4 import java.lang.reflect.Field;
5 import java.lang.reflect.Method;
6
7
8 public class demo2 {
9 public static void main(String[] args) throws Exception {
10 //获取class对象
11 Class cls = Class.forName("com.reflex.bean.Person");
12 String name = cls.getName();
13 System.out.println(name);
14 //获取构造函数对象
15 System.out.println("---------分割线-----------");
16 Constructor[] constructors = cls.getConstructors();
17 for (Constructor con : constructors) {
18 System.out.println(con);
19 }
20 System.out.println("---------分割线-----------");
21 Constructor[] declaredConstructors = cls.getDeclaredConstructors();
22 for (Constructor Dcon : declaredConstructors) {
23 System.out.println(Dcon);
24 }
25 //获取方法对象
26 System.out.println("---------分割线-----------");
27 System.out.println("会获取到继承Object类的方法");
28 Method[] methods = cls.getMethods();
29 for (Method me : methods) {
30 System.out.println(me);
31 }
32 System.out.println("---------分割线-----------");
33 Method[] declaredMethods = cls.getDeclaredMethods();
34 for (Method Dme : declaredMethods) {
35 System.out.println(Dme);
36 }
37 //获取属性对象
38 System.out.println("---------分割线-----------");
39 Field[] fields = cls.getFields();
40 for (Field fi : fields) {
41 System.out.println(fi);
42 }
43 System.out.println("---------分割线-----------");
44 Field[] declaredFields = cls.getDeclaredFields();
45 for (Field Dfi : declaredFields) {
46 System.out.println(Dfi);
47 }
48 System.out.println("---------分割线-----------");
49 Object per = cls.newInstance();
50 Field id = cls.getDeclaredField("Id");
51 //获取和修改private修饰的方法和属性,需要设置暴力反射
52 id.setAccessible(true);
53 id.set(per,"123456");
54 System.out.println(per);
55 }
56 }
反射的使用案例:在不改变代码的情况下获取到不同对象和方法
实现:配置文件+反射(框架设计的雏形)
代码案例:
1 package com.reflex.bean;
2
3 public class Person {
4 private String Id;
5 public String name;
6 public String age;
7 protected String gender;
8
9 public String getId() {
10 return Id;
11 }
12
13 public String getName() {
14 return name;
15 }
16
17 public String getAge() {
18 return age;
19 }
20
21 public String getGender() {
22 return gender;
23 }
24
25 public void setId(String id) {
26
27 Id = id;
28 }
29
30 public void setName(String name) {
31 this.name = name;
32 }
33
34 public void setAge(String age) {
35 this.age = age;
36 }
37
38 public void setGender(String gender) {
39 this.gender = gender;
40 }
41
42 public Person(String id, String name, String age, String gender) {
43
44 Id = id;
45 this.name = name;
46 this.age = age;
47 this.gender = gender;
48 }
49
50 public Person() {
51
52 }
53
54 private void reflexDemo() {
55 System.out.println("this is a test!");
56 }
57
58 @Override
59 public String toString() {
60 return "Person{" +
61 "Id='" + Id + '\'' +
62 ", name='" + name + '\'' +
63 ", age='" + age + '\'' +
64 ", gender='" + gender + '\'' +
65 '}';
66 }
67 private void eat(){
68 System.out.println("eat food!");
69 }
70 }
1 package com.reflex.bean;
2
3
4 public class Student {
5 private String Id;
6 public String name;
7 public String age;
8 protected String gender;
9
10 public String getId() {
11 return Id;
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public String getAge() {
19 return age;
20 }
21
22 public String getGender() {
23 return gender;
24 }
25
26 public void setId(String id) {
27
28 Id = id;
29 }
30
31 public void setName(String name) {
32 this.name = name;
33 }
34
35 public void setAge(String age) {
36 this.age = age;
37 }
38
39 public void setGender(String gender) {
40 this.gender = gender;
41 }
42
43 public Student(String id, String name, String age, String gender) {
44
45 Id = id;
46 this.name = name;
47 this.age = age;
48 this.gender = gender;
49 }
50
51 public Student() {
52
53 }
54
55 private void reflexDemo() {
56 System.out.println("this is a test!");
57 }
58
59 @Override
60 public String toString() {
61 return "Person{" +
62 "Id='" + Id + '\'' +
63 ", name='" + name + '\'' +
64 ", age='" + age + '\'' +
65 ", gender='" + gender + '\'' +
66 '}';
67 }
68 private void study(){
69 System.out.println("study...");
70 }
71 }
1 package com.reflex.demo;
2
3 import java.io.InputStream;
4 import java.lang.reflect.Method;
5 import java.util.Properties;
6
7
8 public class demo3 {
9 public static void main(String[] args) throws Exception{
10 //创建properties对象
11 Properties prop = new Properties();
12 //获取类加载器
13 ClassLoader classLoader = demo3.class.getClassLoader();
14 //通过类加载器获取配置文件
15 InputStream in = classLoader.getResourceAsStream("prop.properties");
16 //加载配置文件
17 prop.load(in);
18 //通过配置文件获取对象的属性
19 String className = prop.getProperty("className");
20 String methodName = prop.getProperty("methodName");
21 //通过反射获取对象
22 Class cls = Class.forName(className);
23 Object obj = cls.newInstance();
24 //获取方法对象
25 Method method = cls.getDeclaredMethod(methodName);
26 //因为方法修饰为private,设置暴力反射(不设置无权访问会报错)
27 method.setAccessible(true);
28 //调用方法
29 method.invoke(obj);
30 }
31 }
配置文件:
名字:
prop.properties
内容:
#className=com.reflex.bean.Person
#methodName=eat
className=com.reflex.bean.Student
methodName=study
获取构造函数、成员属性和成员方法对象的相关操作,建议结合着API文档进行拓展学习!