前言
java语言的反射机制是指能够动态获取信息以及动态调用对象的方法的功能。
一个类中包含成员变量、方法、构造方法、包等等信息,反射机制将class文件读入内存,并为之创建一个Class对象。
一句话,反射是框架设计的灵魂。
反射的使用
获取Class信息
//第一种获取Class对象方式
Designer designer = new Designer("A001","Alex","Designer", 30);
Class designerClass1 = designer.getClass();
System.out.println(designerClass1.getName());
//第二种获取Class对象方式
Class designerClass2 = Designer.class;
System.out.println(designerClass2.getName());
//第三种获取Class对象方式
try {
Class designerClass3 = Class.forName("com.maowei.learning.reflection.pojo.Designer");
System.out.println(designerClass3.getName());
}catch (ClassNotFoundException e){
e.printStackTrace();
}
上述代码列出了获取Class对象的三种方式,第一种方式多此一举,使用反射的目的就是动态创建对象,既然对象已经有了,还要反射作甚;第二种,需要导入类的包,依赖太强,不导包就抛编译错误;一般使用第三种,只需要一个代表包路径的字符串即可。
获取构造方法
Class designerClass3 = Class.forName("com.maowei.learning.reflection.pojo.Designer");
//System.out.println(designerClass3.getName());
Constructor[] conArr = designerClass3.getConstructors();
for(Constructor c : conArr)
System.out.println(c);
System.out.println("===============这是分割线===============");
conArr = designerClass3.getDeclaredConstructors();
for(Constructor c : conArr)
System.out.println(c);
System.out.println("===============这是分割线===============");
Constructor constructor = designerClass3.getConstructor(String.class,String.class,String.class, int.class);
System.out.println(constructor);
System.out.println("===============这是分割线===============");
constructor = designerClass3.getDeclaredConstructor();
System.out.println(constructor);
上述代码列出了两种获取构造方法:
批量的方法:
public Constructor[] getConstructors():所有”公有的”构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)获取单个的方法:
public Constructor getConstructor(Class… parameterTypes):获取单个的”公有的”构造方法:
public Constructor getDeclaredConstructor(Class… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;
有了构造方法之后便可调用newInstance方法创建对象,
Constructor constructor = designerClass3.getConstructor(String.class,String.class,String.class, int.class);
Object obj1 = constructor.newInstance("A001","Alex","Designer", 30);
constructor = designerClass3.getDeclaredConstructor();
con.setAccessible(true);//暴力访问(忽略掉访问修饰符)
Object obj2 = constructor.newInstance();
获取成员方法
Constructor constructor = designerClass3.getConstructor(String.class,String.class,String.class, int.class);
Object obj1 = constructor.newInstance("A001","Alex","Designer", 30);
Method[] methods = designerClass3.getMethods();
for(Method m : methods){
System.out.println(m);
}
System.out.println("===============这是分割线===============");
methods = designerClass3.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
跟构造方法一样,上述代码也列出了两种获取成员方法:
批量的方法:
public Method[] getMethods():所有”公有的”构造方法
public Method[] getDeclaredMethods():获取所有的构造方法(包括私有、受保护、默认、公有)获取单个的方法:
public Method getMethod(String name, Class< ? >… parameterTypes):获取单个的”公有的”构造方法:
public Method getDeclaredMethod(String name, Class< ? >… parameterTypes):获取”某个构造方法”可以是私有的,或受保护、默认、公有;
获取Method对象之后可以调用invoke方法实现对成员方法的访问
Method method = designerClass3.getMethod("doWorking");
method.invoke(obj1);
System.out.println("===============这是分割线===============");
method = designerClass3.getDeclaredMethod("working02");
method.setAccessible(true);
method.invoke(obj1);
获取成员变量
Field[] fields = designerClass3.getFields();
for(Field f : fields){
System.out.println(f);
}
System.out.println("===============这是分割线===============");
fields = designerClass3.getDeclaredFields();
for(Field f : fields){
System.out.println(f);
}
此处 getFields() 方法和 getDeclaredFields() 方法的区别相信大家已经知道了,就是权限修饰符的不同。
当获取了Field对象之后,我们可以进行修改操作,
Field f = designerClass3.getField("age");
f.set(obj1, 31);
System.out.println("===============这是分割线===============");
f = designerClass3.getDeclaredField("id");
f.setAccessible(true);
f.set(obj1,"A002");
反射模式对单例模式的破坏
由于权限控制是程序编译期的处理机制,而反射处理发生在程序的运行期,上述代码也证明了可以通过反射的方式访问对象的私有构造方法,这便会对单例模式造成破坏,因此在使用时格外注意。
总结
本文大体介绍了反射机制的一些用法,完整的反射机制肯定复杂很多,正如开篇提到的“反射是框架设计的灵魂”,只有熟练理解了反射机制,才能写出高质量的框架代码。