前言
反射库(reflection library) 提供了一个非常丰富且精心设计的工具集,以便编写能够动态操纵Java代码的程序。这项功能被大量的运用于JavaBeans中,它是Java组件的体系结构。
一、反射是什么?
在《Java核心技术 卷1》中介绍到反射的定义;
能够分析类能力的程序称为反射(reflective)。
什么是能够分析类能力呢?
可以理解为程序运行时可以访问、检测和修改他本身状态和行为的能力。包类的属性、方法和构造器等。
二、Class类
在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个标识跟踪着每个对象的所属信息。虚拟机利用运行时类型信息选择相应的执行方法。
然而可以通过Java类访问这些信息。保存这些信息的类被称为Class。
Object类中的getClass()方法会返回一个Class类的实例。
接下来介绍三种获取class对象的方法:
由于Object类是所有类的父类,所以可以得到获取Class类的第一种方法:
//通过对象.getClass方法获取。
User user = new User();
Class<? extends User> aClass = user.getClass();
还可以通过调用静态方法的方法forName(className)获得类名对应的Class对象。
//通过静态方法获取Class
Class<?> aClass1 = Class.forName("java.lang.Math");//参数:类路径
System.out.println("name:"+ aClass1.getName());
//控制台打印:name:java.lang.Math
forName(classNmae)方法调用时,只有className是类名或者是接口名时才可以使用,否则会抛出一个检查时异常。所以无论何时使用这个方法都应该提供一个异常处理器。
最后可以通过.class的方式获取Class对象。
Class<User> userClass = User.class;
上面的示例代码中可以发现,Class类其实是一个泛型类。
getNmae应用于数组类型的时候,会返回一个奇怪的名字
System.out.println("Integer[].class.getName()===="+ Integer[].class.getName());
System.out.println("Double[].class.getName()====" + Double[].class.getName());
System.out.println("int[].class.getName()====" + int[].class.getName());
//Integer[].class.getName()====[Ljava.lang.Integer;
//Double[].class.getName()====[Ljava.lang.Double;
//int[].class.getName()====[I
Class还有一个很实用的方法:newInstance(),可以用来动态的创建一个类的实例。newInstance()方法调用默认的构造器初始化新创建对象,如果类中没有这个对象,则会抛出异常。
如果想要调用有参数的构造器,就需要Constructor类中的newInstance(Object[] args);后续会进行讲解
Object o = aClass.newInstance();
System.out.println(o.toString());
三、利用反射分析类的能力
下面简要介绍一下反射机制的最重要的内容——检查类的结构。
- 在java.lang.reflect包中提供了三个类:Field、Method和Constructor分别用于描述属性,方法和构造器。
- Class类中的getFields()、getMethods()、getConstructors()方法用于返回类提供的public 属性方法和构造器数组,其中包括超类的公共成员。
- Class类中getDeclaredFields()、getDeclaredMethods()、
getDeclaredConstructors()方法用于返回类提供的全部属性方法和构造器数组,包括私有的和受保护的成员,但不包括超类的成员。
示例代码
创建一个User对象,包含公共和私有的属性和构造器,并继承Person对象
创建一个Person对象,包含公共和私有的属性和构造器;
public class User extends Person{
public String name;
private int age;
public User(String name) {
this.name = name;
}
public User() {
}
protected User(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Person {
public String nation;
private String desc;
public Person(String nation) {
this.nation = nation;
}
private Person(String nation, String desc) {
this.nation = nation;
this.desc = desc;
}
public Person() {
}
public String getNation() {
return nation;
}
public void setNation(String nation) {
this.nation = nation;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
获取Class对象,并通过class获取对象的属性,方法和构造器。
public class Reflective {
public static void main(String[] args) throws Exception {
Class<?> clazz = Class.forName("reflect.User");//参数:类路径
Field[] fields = clazz.getFields();
System.out.println("getFields 方法获取的属性:");
for (Field field : fields) {
System.out.println(field.getName());
}
Field[] declaredFields = clazz.getDeclaredFields();
System.out.println("getDeclaredFields 方法获取的属性:");
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
}
Method[] methods = clazz.getMethods();
System.out.println("getMethods 方法获取的方法:");
for (Method method : methods) {
System.out.println(method.getName());
}
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println("getDeclaredMethods 方法获取的方法:");
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod.getName());
}
Constructor<?>[] constructors = clazz.getConstructors();
System.out.println("getConstructors 方法获取的构造器:");
for (Constructor<?> constructor : constructors) {
System.out.println("构造器参数个数:"+constructor.getParameterCount());
}
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
System.out.println("getDeclaredConstructors 方法获取的构造器:");
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println("构造器参数个数:"+ declaredConstructor.getParameterCount());
}
}
}
四、通过反射创建实例对象
通过反射可以获取动态实例化对象:
Class<?> clazz = Class.forName("reflect.User");//参数:类路径
Object o = clazz.newInstance();
System.out.println(o.toString());
Object zhansan = clazz.getConstructor(String.class).newInstance("zhansan");
System.out.println(zhansan);
后续还会补充反射的更多用法~~并完善文章