一、什么是RTTI
在java中,能让程序在运行时识别对象和类的信息的方法有两种,一种是传统的RTTI(Run-Time Type Identification)运行时类型类型信息识别,另一种是反射。
对于RTTI,它假设我们在编译时已经知道是哪种类型,反射是允许我们在运行时发现和使用类的信息。
二、什么是反射?
反射是指在运行过程中,任意一个类都能够知道这个类里的所有属性和方法,对任意一个对象都能够调用它的任意一个属性或方法,这种动态的获取信息和调用对象方法的功能就叫做反射。
三、类的加载流程
每一个类在编译后都会生成一个对应的以.class为后缀名的文件,在创建一个对象或使用类里面的静态成员时,就会加载这个类。每个类都会产生对应的class对象,在加载这个类时,类加载器首先会去检查这个类的class对象是否被加载过,若尚未加载,默认的类加载器就会根据类名查找对应的.class文件,将文件加载到JVM中,然后创建一个class对象,下一步会验证代码是否规范,并给一些静态成员分配空间,如果该类有超类,则对其初始化,并执行静态初始化器和静态初始化块。
四、利用反射动态创建对象
1、获取class对象的三种方式
创建一个Animal类
package edu.reflex.demo1.Animal
public class Animal {
private String name;
private String sex;
private int age;
public Animal(){
}
public Animal(String name, String sex, int age) {
this.name = name;
this.sex = sex;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Animal [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
1.1、通过Class.forName获取
//className必须是全路径名称;
//Class.forName()有异常:ClassNotFoundException
try {
Class clazz = Class.forName("edu.reflex.demo1.Animal");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
1.2、通过类名.Class获取
/**
* 利用class属性获取字节码文件(类.class:需要输入一个明确的类,
* 任意一个类型都有一个静态的class属性)
*/
Class clazz = Animal.class;
1.3、通过对象名.getClass()获取
// 利用getClass()方法获取对象的class 对象
Animal animal = new Animal();
Class clazz = animal.getClass();
2、动态创建对象
2.1、使用newInstance()方法创建对象
// 通过newInstance()方法来创建对应类的实例
// 使用这个方法要求class对象对应的类必须要有默认构造器,
// 也就是无参构造方法
try {
Object obj = clazz.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
2.2、使用构造方法创建对象
// 使用Class对象获取指定的Constructor对象,调用Constructor对象的
// newInstance()方法来创建Class对象对应类的实例。这个方法可以使用Class
// 对象对应类的任意指定的构造器来创建实例
try {
Constructor construct = clazz.getConstructor(String.class,String.class,int.class);
Object obj = construct.newInstance("狗","公",3);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
五、利用反射调用方法
//获取class对象
Class clazz = Class.forName("edu.reflex.demo1.Animal");
//反射创建类的实例
Animal obj = (Animal) c1.newInstance();
obj.setName("人");
//通过反射获取到method对象
Method m = c1.getMethod("getName");
//通过method对象的invoke方法调用方法
Object o = m.invoke(obj);
System.out.println(o);
六、动态操作属性(调用get,set方法)
获取属性:
//获取class对象
Class clazz = Class.forName("edu.etime.reflex.demo1.Animal");
//反射创建类的实例
Animal obj = (Animal) clazz .newInstance();
//获取公有属性
Field[] fileds = clazz .getFields();
for(Field f :fileds){
System.out.println("公有属性:"+f.getName());
}
Field[] fileds2 = clazz .getDeclaredFields();
for(Field f :fileds2){
System.out.println("私有属性:"+f.getName());
}
给属性赋值:
Field[] fileds2 = clazz.getDeclaredFields();
for(Field f :fileds2){
System.out.println("私有属性:"+f.getName());
f.setAccessible(true);
if(f.getType().equals(String.class)){
f.set(obj, "123");
}else if(f.getType().equals(int.class)){
f.set(obj, 123);
}
}
System.out.println(obj.toString());
调用get、set方法:
PropertyDescriptor p = new PropertyDescriptor("name",clazz);
//获取写方法
Method mset = p.getWriteMethod();
mset.invoke(obj, "你好");
//获取读方法
Method mget = p.getReadMethod();
System.out.println(mget.invoke(obj));
或者
//或者(拼接一个get或则set方法的名称)
String fname = "name";
String mname = "get"+fname.substring(0,1).toUpperCase()+fname.substring(1);//getName
Method m = clazz.getMethod(mname);
System.out.println(m.invoke(obj));