作者 | ewenll
责编 | 夕颜
出品 | CSDN博客
-
一种是传统的RTTI(Run-Time Type Identification),它假定我们在编译时已经知道了所有的类型信息; -
另一种是反射机制,它允许我们在运行时发现和使用类的信息。使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
-
类名.class:该方法最为安全可靠,程序性能更高。这说明任何一个类都有一个隐含的静态成员变量 class。这种方法只适合在编译前就知道操作的 Class,多用于传递参数。 -
Class.forName(“类的全路径名”) :当知道某类的全路径名时,可以使用此方法获取 Class 类对象。用的最多,但可能抛出 ClassNotFoundException 异常,多用于加载配置文件。 -
对象名.getClass():getClass()是Object中的方法,java中所有类都直接或间接继承了Object类,所以都有getClass()方法。
//ewen包下的Person类
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
//构造函数、get、set方法省略。
public void sleep(){
System.out.println("sleep....");
}
}
public class ReflectTest {
public static void main(String[] args) throws Exception {
//获取Person类的Class对象
// 通过类名.class获取
Class clazz1 = Person.class;
//通过Class.forName("类的全路径名")
Class clazz2 = Class.forName("ewen.Person");
//通过对象名.getClass()方法获得
Person person = new Person();
Class clazz3 = person.getClass();
System.out.println(clazz1 == clazz2); //true
System.out.println(clazz2 == clazz3); //true
}
}
-
Field[] getFields() :获取所有public修饰的成员变量,返回一个含有所有public修饰的成员变量对象的数组; -
Field getField(String name):获取指定名称的 public修饰的成员变量,返回一个成员变量对象。 -
Field[] getDeclaredFields() :获取所有的成员变量,不考虑修饰符。 -
Field getDeclaredField(String name) :获取指定名称的成员变量对象,不考虑修饰符。
//获取所有pubic修饰的成员变量
Field[] fields = clazz1.getFields();
for (Field field : fields) {
System.out.println(field); //public java.lang.String ewen.Person.a,只有a是public修饰的
}
//获取指定的成员变量
Field field = clazz1.getField("a");
System.out.println("成员变量a:" + field); /public java.lang.String ewen.Person.a
//使用getField()方法获取非public修饰的方法,报NoSuchFieldException
/* Field field2 = clazz1.getField("b");
System.out.println("protected修饰的b" + field2);*/
//获取所有成员变量
Field[] fields2 = clazz1.getDeclaredFields();
for (Field field1 : fields2) {
System.out.println(field1); //所有成员变量
}
//获取指定成员变量,不考虑修饰符
Field field3 = clazz1.getDeclaredField("d");
System.out.println(field3); /public java.lang.String ewen.Person.d
-
Constructor<?>[] getConstructors() :获取所有public 修饰的构造方法,返回一个含有所有public修饰的构造函数对象的数组。 -
Constructor getConstructor(类<?>… parameterTypes) :获取含有指定参数public修饰的构造函数。 -
Constructor<?>[] getDeclaredConstructors() :获取所有构造函数,不考虑修饰符。 -
Constructor getDeclaredConstructor(类<?>… parameterTypes) :获取所有构造函数,不考虑修饰符,参数是构造器中参数类型对应的Class对象。
//获取构造函数
Constructor con = clazz1.getDeclaredConstructor(String.class, int.class);
System.out.println(con); //private ewen.Person(java.lang.String,int)
-
Method[] getMethods() :获取所有public修饰的方法,返回一个含有所有public修饰的方法对象的数组。 -
Method getMethod(String name, 类<?>… parameterTypes) :获取public修饰的含有指定参数的方法。 -
Method[] getDeclaredMethods() :获取所有方法,不考虑修饰符 -
Method getDeclaredMethod(String name, 类<?>… parameterTypes) :获取指定方法,不考虑修饰符。
-
设置成员变量值:field.set(类对象名,value)
//获取指定的成员变量
Field field = clazz1.getField("a");
System.out.println("成员变量a:" + field);
Person person2 = new Person();
//设置值
field.set(person2,"aaa");
System.out.println("a的值:" + person2.getA()); //a的值:aaa
-
获取成员变量值:field.get(类对象名)
//获取指定的成员变量
Field field = clazz1.getField("a");
System.out.println("成员变量a:" + field);
Person person2 = new Person();
//获取person2中的a的值
Object value = field.get(person2);
System.out.println("a的值:" + value); //a的值为null,String类型的成员变量默认为null。
-
忽略访问权限修饰符的安全检查:field.setAccessible(true)
//获取指定成员变量,不考虑修饰符
Field field3 = clazz1.getDeclaredField("d");
System.out.println(field3);
//设置值
Person person1 = new Person();
/*
忽略访问权限修饰符的安全检查,d是private修饰的,如果不忽略
访问权限修饰符的安全检查,会报IllegalAccessException异常。
*/
field3.setAccessible(true);
field3.set(person1,"111");
System.out.println("d的值:" + person1.getD()); //d的值:111
-
创建对象:T newInstance(Object… initargs) ,里面为可变参数,变量的值。
/获取构造函数
Constructor con1 = clazz1.getConstructor(String.class);
//创建对象
Object person3 = con1.newInstance("张三");
Object person4 = clazz1.newInstance();
-
执行方法:Object invoke(类对象名, Object… args) ,参数必须得有类对象,变量参数根据方法参数来定
//获取方法对象
Method method = clazz1.getMethod("sleep");
//执行方法
method.invoke(person1);
-
获取方法名称 String getName()
pro.properties文件:
pro.className=ewen.Person
pro.methodName=sleep
public class UseReflect {
public static void main(String[] args) throws Exception {
//加载配置文件
/*
创建Properties对象。
Properties是Java中jdk自带的一个对象
我们可以直接将后缀为properties的文件变为Properties对象,
然后通过Porperties对象中的方法对.properties文件对象进行操作
*/
Properties pro = new Properties();
//获得配置文件(pro.properties)的字节流
InputStream is = UseReflect.class.getClassLoader().getResourceAsStream("pro.properties");
//从输入流中读取属性列表(键和元素对)。
pro.load(is);
//获取配置文件中定义的数据
String className = pro.getProperty("pro.className");
String methodName = pro.getProperty("pro.methodName");
//获取Class对象
Class clazz = Class.forName(className);
//获取类对象
Object obj = clazz.newInstance();
//获取方法对象
Method method = clazz.getMethod("sleep");
//执行方法
method.invoke(obj);
}
}
-
反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。 -
通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。 -
使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。
【END】
更多精彩推荐
☞深度学习先驱 Yann LeCun 被骂到封推!AI 偏见真该甩锅数据集?
☞他被称为"中国第一程序员",一人之力单挑微软,如今拜入武当修道
欢迎“分享”、“点赞”、“在看”三连走起!
文章评论