Java学习之反射

时间:2019-08-19
本文章向大家介绍Java学习之反射,主要包括Java学习之反射使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

反射

作用:

把一个对象的成员变量、构造方法、成员函数(方法)转换为对象,然后进行动态调用。反射是框架设计的“灵魂”技术!

注意:

代码对象从创建到产生结果的过程中,要经历过编译,加载,运行,三个阶段。

编译:将 .Java 文件转换为字节码 .class 文件。(此时代码还存在于硬盘中)

加载:将 .class 文件加载到内存中,以便编辑器进行操作。

运行:使内存中的代码产生结果。

类加载器:

加载:

指的是将类的class文件读入到内存,并为之创建一个java.lang.Class对象,也就是说,当程序中使用任何类时,系统都会为之建立一个java.lang.Class对象。

类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。

通过使用不同的类加载器,可以从不同来源加载类的二进制数据,通常有如下几种来源。

  • 从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式。
  • 从JAR包加载class文件,这种方式也是很常见的,前面介绍JDBC编程时用到的数据库驱动类就放在JAR文件中,JVM可以从JAR文件中直接加载该class文件。
  • 通过网络加载class文件。

把一个Java源文件动态编译,并执行加载。

类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类。

作用:

  • 将硬盘上的Class文件加载到内存(方法区)以便后续的操作。
  • 类加载器加载完成后会在堆区创建一个class对象,用来表示加载的“类结构”。

反射的第一步:获取到堆中的class对象

方法:

  • Class.forName (全限定类名) 获取Class对象(然后cls.newInstance() 获取实例化对象),这种一般配合配置文件使用
  •  类名.Class 获取响应类型的clszz 对象,常用于参数列表用于传参
  •  对象名.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文档进行拓展学习!

原文地址:https://www.cnblogs.com/Bernard94/p/11380348.html