【学习笔记】Java反射
作为一门静态语言,反射机制让Java有了准动态的特性。
静态与动态
作为一个从2017年进入大学并开始学习计算机科学的学生,在我入门计算机的时代,中文互联网上使用广泛的著名语言有:C、C++、Java、Python等。我很早就知道了前三者属于静态语言,而Python属于动态语言。但是很久之后,主观上只觉得作为动态语言的Python写起来更加方便,并没有真正理解动静态语言的本质区别。而理解其中真正的区别,是很有必要的。
动态语言:动态语言在运行时代码可以根据某些条件改变自身结构。
静态语言:运行时结构不可变的语言。
反射与动静态:反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。反射可以实现动态创建对象和编译,体现出很大的灵活性。但是反射对性能有影响。
正常编程方式与反射的区别
方式 | 使用过程 |
---|---|
正常方式 | 引入需要的“包类”名称 -> 通过new实例化 -> 取得实例化对象 |
反射方式 | 实例化对象 -> getClass()方法 -> 得到完整的“包类”名称 |
初试Reflection API
单看概念还是过于晦涩难懂,不如用代码来尝试一下反射的基础使用。
我们以如下POJO类为例:
package main.java.reflection;
//User类
class User {
private String name;
private int id;
private int age;
//无参和有参构造方法
public User() {
}
public User(String name, int id, int age) {
this.name = name;
this.id = id;
this.age = age;
}
//get方法
public String getName() {
return name;
}
public int getId() {
return id;
}
public int getAge() {
return age;
}
//set方法
public void setName(String name) {
this.name = name;
}
public void setId(int id) {
this.id = id;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", id=" + id +
", age=" + age +
'}';
}
利用API获取包类:
public class RTest1 {
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Class.forName("main.java.reflection.User");
System.out.println(c1);
}
}
运行结果:
class main.java.reflection.User
以上只是Java反射的一个小小使用,反射机制提供的功能远不止于此。
获取类的运行时结构
我们接着用代码来尝试获取类的运行时结构:
User user = new User();
Class c1 = user.getClass();
//获得类的名字
System.out.println(c1.getName());
System.out.println(c1.getSimpleName());
//获得类的属性
Field[] fields = c1.getFields(); //只能找到public属性
fields = c1.getDeclaredFields(); //找到全部属性
for (Field field : fields) {
System.out.println(field);
}
//获取指定属性的值
Field name = c1.getDeclaredField("name");
System.out.println(name);
//获得类的方法
Method[] methods = c1.getMethods();//获得本类及其父类的全部public方法
for (Method method : methods) {
System.out.println("getMethods:" + method);
}
methods = c1.getDeclaredMethods();//或得本类的所有方法
for (Method method : methods) {
System.out.println("getDeclaredMethods:" + method);
}
结合上述的示例,我们对利用Java反射获取属性、方法、构造器的名称、修饰符等。
动态创建对象执行方法
到目前为止,我们见识了利用反射方法获取Class对象的方式。那么,获取到的这些Class对象能做什么呢?
依然用代码示例来介绍:
//获得Class对象
Class c1 = Class.forName("main.java.reflection.User");
//构造一个对象
User user = (User)c1.newInstance();//本质上是调用了类的无参构造器
System.out.println(user);
//通过构造器创建对象
Constructor constructor = c1.getDeclaredConstructor(String.class,int.class,int.class);
User user1 = (User)constructor.newInstance("庆庆",000,22);
System.out.println(user1);
//通过反射调用普通方法
User user2 = (User) c1.newInstance();
//通过反射获取一个方法
Method setName = c1.getDeclaredMethod("setName", String.class);
setName.invoke(user2,"庆庆");
System.out.println(user2);
//通过反射操作属性
User user3 = (User)c1.newInstance();
Field name = c1.getDeclaredField("name");
//不能直接操作私有属性,需要关闭程序的安全检测,属性或方法的setAccessible(true)
name.setAccessible(true);
name.set(user3,"庆庆1");
System.out.println(user3);
获取泛型信息
待更新ing
获取注解信息
待更新ing