0%

Java反射学习笔记

前言

这个是个人学习Java相关反射时所总结的入门笔记,对反射的理解还不够深入;

1. 问题导入

1.1 如何看待面向对象的封装性和反射机制?两者是否矛盾?

答:两者并不矛盾。封装性相当于是建议其他类去调用当前类的公共方法,而私有方法不建议去调用,因为公共的方法可能比私有的方法更好,在公共方法里面可能添加了一些私有方法没有的逻辑。如果非要调用私有的方法,也可以调用,那我们就通过反射的方式去调用。(总结:封装性解决的是访问权限。即建议调用哪个的问题;反射解决的是调用类的问题 ,即能不能调的问题。)

1.2 开发中到底用直接new还是反射的方式调用公共结构?

建议:直接使用new的方式调用公共结构;

什么时候会用反射的方式:反射的特征是动态性,在编译时无法确定要new哪个类的对象时可以选用反射;

2. 反射常用API的使用

2.1 获取反射中的Class实例

2.1.1 调用Class的静态方法:Class.forname(String classPath)

当可以知道该类的全路径名时,推荐优先使用使用该方法获取 Class 类对象;

1
Class clazz = Class.forName("java.lang.String");

2.1.2 调用运行时类的属性:类名.class

这种方法只适合在编译前就知道操作的 Class;

1
Class clazz = String.class;

2.1.3 通过运行时类的对象:对象名.getClass()

1
2
String str = new String("Hello");
Class clazz = str.getClass();

2.1.4 使用类的加载器:ClassLoader

1
2
ClassLoader classLoader = String.class.getClassLoader();
Class clazz = classLoader.loadClass("java.lang.String")

2.2 创建运行时类的对象

2.2.1 通过 Class类对象的 newInstance() 方法

1
2
Class clazz = String.class;
String str = (String)clazz.newInstance();

2.2.2 通过 Constructor构造器对象的 newInstance() 方法

1
2
3
Class clazz = String.class;
Constructor constructor = clazz.getConstructor();
String str = (String)constructor.newInstance();

值得注意的是:通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法。

2.3 获取运行时类的属性、方法、构造器

2.3.1 获取运行时类的属性

  • getFields():获取当前运行时类及其父类中声明为public访问权限的属性;
  • getDeclaredFields():获取当前运行时类中声明的所有属性(不包括父类中声明的属性);

2.3.2 获取运行时类的方法

  • getMethods():获取当前运行时类及其父类中声明为public访问权限的方法;
  • getDeclaredMethods():获取当前运行时类中声明的所有方法(不包括父类中声明的属性);

2.3.3 获取运行时类的构造器

  • getConstructors():获取当前运行时类中声明为public访问权限的构造器;
  • getDeclaredConstructors():获取当前运行时类中声明的所有构造器;

2.4 调用运行时类的指定属性、方法

2.4.1 调用运行时类的指定属性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//以自定义类Person为例:
Class<Person> clazz = Person.class;
//创建运行时类的对象
Person p = clazz.newInstance();

//获取运行时类中指定变量名的属性
Field name = Person.class.getDeclaredField("name");

//保证当前属性时可访问的
name.setAccessible(true);

//获取、设置指定对象的此属性值
//set():参数1指明设置哪个对象的属性,参数2设置具体的当前属性值
name.set(p, "Tom")
//get():参数指明获取哪个对象的当前属性值
System.out.println(name.get(p));

2.4.2 调用运行时类的指定方法

一、对于非静态方法:

1
2
3
4
5
6
7
8
9
10
11
12
//以自定义类Person为例:
Class<Person> clazz = Person.class;
//创建运行时类的对象
Person p = clazz.newInstance();

//获取指定的某个方法
Method show = clazz.getDeclaredMethd(方法名, 可变形参);
//保证当前方法是可访问的
show.setAccessible(true);
//调用invoke()
// invoke():参数1是方法的调用者,参数2是给方法形参赋值的实参,invoke()的返回值即为对应类中调用的方法的返回值
show.invoke(p, 实参)

二、对于静态方法

1
2
3
4
Method showDesc = clazz.getDeclaredMethd(方法名);
showDesc.setAccessible(true);
//静态方法使用当前类去调用,使用当前类.class的形式
showDesc.invoke(Person.class)