今天复习一下反射,说是复习,基本上已经忘干净了,只知道用Spring、Mybatis、JavaFX 的时候加个注解,具体原理就不知道了。所以必须再深入学习一下。
设计一个框架需要什么技术?
反射机制、自定义注解、设计模式、AOP技术、Netty、Spring 架构、SpringBoot 自定义插件、多线程或 JUC。
反射机制的核心是在运行时动态地获取类的信息,并通过这些信息来调用类的成员变量和方法,这种能力使得Java程序可以在运行时动态地加载和执行代码,从而实现更加灵活和动态的功能。
我们以往的学习经历告诉我们,初始化对象的方式无非就是直接 new:
User user = new User();
下面给出两种通过反射初始化对象的方式:
原理:Class 对象的 newInstance 方法会默认执行我们的无参构造方法来初始化对象(所以在定义一个 JavaBean的时候一定要记得写无参构造的方法)。
- // 通过反射调用无参构造来初始化对象
- Class> aClass = Class.forName("kt.pojo.User");
- // newInstance() 默认执行到我们的无参构造方法来初始化对象
- User user = (User) aClass.newInstance();
- System.out.println(user);
- package kt.pojo;
-
- import java.util.Objects;
-
- public class User {
- public String name;
- public Integer age;
-
- public User(){}
-
- public User(String name, Integer age) {
- this.name = name;
- this.age = age;
- }
-
- @Override
- public String toString() {
- return "User{" +
- "name='" + name + '\'' +
- ", age=" + age +
- '}';
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- User user = (User) o;
- return age.equals(user.age) && Objects.equals(name, user.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(name, age);
- }
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public int getAge() {
- return age;
- }
-
- public void setAge(Integer age) {
- this.age = age;
- }
- }
注意:这里的 age 属性类型也可以用 int ,区别就是 int 的默认值为 0,Integer 的默认值为 null。
输出结果:
User{name='null', age=null}
通过我们 Class 对象来获取我们的构造器对象 Constructor,然后调用 Constructor 对象的 newInstacne 方法来实现有参构造。
注意:如果 age 属性类型是 int,那么 getConstructor 的第二个参数应该是 int.class 。
- // 通过反射调用有参构造来初始化对象
- Class> aClass = Class.forName("kt.pojo.User");
- // 通过反射调用有参构造来初始化对象
- Constructor> constructor = aClass.getConstructor(String.class, Integer.class);
- User tom = (User) constructor.newInstance("tom", 10);
- System.out.println(tom);
输出结果:
User{name='tom', age=10}
我们通过反射获取到对象,然后调用对象的方法来赋值(必须保证对象的 setter 方法是 public 的):
- User user = (User) aClass.newInstance();
- user.setName("tom");
- user.setAge(10);
- System.out.println(user);
运行结果:
User{name='tom', age=10}
通过反射获取到 Class 对象,再调用 Class 对象的 getDeclareField 方法获得指定属性的属性对象,最后通过属性的 set 方法来实现赋值:
- User user = (User) aClass.newInstance();
- // aClass.getField(); //这个方法会把我们 User 类的父类(这里是Object)中的属性页获取到
- Field name = aClass.getDeclaredField("name");
- name.setAccessible(true); // 如果属性是私有的(private) 就需要添加访问权限
- Field age = aClass.getDeclaredField("age");
- age.setAccessible(true); // 如果属性是私有的(private) 就需要添加访问权限
- name.set(user,"tom");
- age.set(user,10);
- System.out.println(user);
注意:
我们在上面的 User 类中添加一个 sayHello 方法:
- public void sayHello(String name){
- System.out.println("hello "+name);
- }
通过 Class 对象的 getDeclaredMethod 方法获取到指定的方法对象 Method,最后调用 Method 对象的 invoke 方法(需要传入执行该方法的对象和需要的参数):
- Class> aClass = Class.forName("kt.pojo.User");
- User user = (User)aClass.newInstance();
- Method toString = aClass.getDeclaredMethod("sayHello", String.class);
- toString.invoke(user,"Tom");
运行结果:
hello Tom