java+反射不成功_Java学习之反射

本文详细介绍了Java反射的作用、类加载器的工作原理以及如何通过反射获取类的构造函数、成员变量和方法对象。通过代码案例展示了Class对象的获取方式,并通过反射实现对象的实例化和方法调用。最后,探讨了反射在框架设计中的重要性,以及在不改变代码的情况下,如何通过反射和配置文件实现动态调用不同对象和方法。
摘要由CSDN通过智能技术生成

反射

作用:

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

注意:

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

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

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

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

类加载器:

加载:

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

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

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

从本地文件系统加载class文件。

从JAR包加载class文件。

通过网络加载class文件。

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

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

作用:

将硬盘上的Class文件加载到内存(方法区)以便后续的操作。

类加载器加载完成后会在堆区创建一个class对象,用来表示加载的“类结构”。

605b22118153609eee75192796486583.png

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

方法:

Class.forName (全限定类名) 获取Class对象(然后cls.newInstance() 获取实例化对象),这种一般配合配置文件使用

类名.Class 获取响应类型的class对象,常用于参数列表用于传参

对象名.getClass() 用于方法内部,用于确定传入参数的具体类型

代码案例:

1 package com.reflex.bean;2

3 public classPerson {4 privateString Id;5 publicString name;6 publicString age;7 protectedString gender;8

9 publicString getId() {10 returnId;11 }12

13 publicString getName() {14 returnname;15 }16

17 publicString getAge() {18 returnage;19 }20

21 publicString getGender() {22 returngender;23 }24

25 public voidsetId(String id) {26

27 Id =id;28 }29

30 public voidsetName(String name) {31 this.name =name;32 }33

34 public voidsetAge(String age) {35 this.age =age;36 }37

38 public voidsetGender(String gender) {39 this.gender =gender;40 }41

42 publicPerson(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 publicPerson() {51

52 }53

54 private voidreflexDemo() {55 System.out.println("this is a test!");56 }57

58 @Override59 publicString toString() {60 return "Person{" +

61 "Id='" + Id + '\'' +

62 ", name='" + name + '\'' +

63 ", age='" + age + '\'' +

64 ", gender='" + gender + '\'' +

65 '}';66 }67 private voideat(){68 System.out.println("eat food!");69 }70 }

1 package com.reflex.demo;2

3 import com.reflex.bean.Person;4

5 public classdemo1 {6 public static voidmain(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 cls2 = Person.class;11 //3、 对象名.getClass() 用于方法内部,用于确定传入参数的具体类型

12 Person person = newPerson();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 getConstructor​(Class>... parameterTypes) 返回一个 Constructor对象,该对象反映由该 Class对象表示的类的指定公共构造函数。

Constructor>[] getConstructors​() 返回一个包含 Constructor对象的数组, Constructor对象反映了由该 Class对象表示的类的所有公共构造函数。

Constructor 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 classdemo2 {9 public static voidmain(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 classPerson {4 privateString Id;5 publicString name;6 publicString age;7 protectedString gender;8

9 publicString getId() {10 returnId;11 }12

13 publicString getName() {14 returnname;15 }16

17 publicString getAge() {18 returnage;19 }20

21 publicString getGender() {22 returngender;23 }24

25 public voidsetId(String id) {26

27 Id =id;28 }29

30 public voidsetName(String name) {31 this.name =name;32 }33

34 public voidsetAge(String age) {35 this.age =age;36 }37

38 public voidsetGender(String gender) {39 this.gender =gender;40 }41

42 publicPerson(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 publicPerson() {51

52 }53

54 private voidreflexDemo() {55 System.out.println("this is a test!");56 }57

58 @Override59 publicString toString() {60 return "Person{" +

61 "Id='" + Id + '\'' +

62 ", name='" + name + '\'' +

63 ", age='" + age + '\'' +

64 ", gender='" + gender + '\'' +

65 '}';66 }67 private voideat(){68 System.out.println("eat food!");69 }70 }

1 package com.reflex.bean;2

3

4 public classStudent {5 privateString Id;6 publicString name;7 publicString age;8 protectedString gender;9

10 publicString getId() {11 returnId;12 }13

14 publicString getName() {15 returnname;16 }17

18 publicString getAge() {19 returnage;20 }21

22 publicString getGender() {23 returngender;24 }25

26 public voidsetId(String id) {27

28 Id =id;29 }30

31 public voidsetName(String name) {32 this.name =name;33 }34

35 public voidsetAge(String age) {36 this.age =age;37 }38

39 public voidsetGender(String gender) {40 this.gender =gender;41 }42

43 publicStudent(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 publicStudent() {52

53 }54

55 private voidreflexDemo() {56 System.out.println("this is a test!");57 }58

59 @Override60 publicString toString() {61 return "Person{" +

62 "Id='" + Id + '\'' +

63 ", name='" + name + '\'' +

64 ", age='" + age + '\'' +

65 ", gender='" + gender + '\'' +

66 '}';67 }68 private voidstudy(){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 classdemo3 {9 public static voidmain(String[] args) throws Exception{10 //创建properties对象

11 Properties prop = newProperties();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文档进行拓展学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值