1、在反射机制的处理过程中不仅仅是实例化对象的处理操作,还有类的组成结构操作,类的组成结构:父类、父接口
包、属性、方法等
2、获取类的基本信息
获取指定类的Class对象:Class<?> cls = Person.class ;
获取类所在的包名称:public Package getPackage()
获取父类的定义:public Class<? super T> getSuperclass()
获取父接口的定义:public Class<?>[] getInterfaces()
当获取了一个类的Class对象之后就可以获取这个类的所有继承结构信息。
2、反射调用构造方法
实例化方法替代: clazz.getDeclaredConstructor().newInstance()
所有类的构造方法都可以通过Class类来完成:
获取本类所有构造方法:public Constructor<?>[] getDeclaredConstructors() throws SecurityException
获取本类指定构造方法:public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
获取所有构造方法:public Constructor<?>[] getConstructors() throws SecurityException
获取指定构造方法:public Constructor<T> getConstructor(Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
(两大类的方法实际上无区别)例:
Class<?> cls = Person.class ; //获取指定类的Class对象
Constructor<?> constructor = cls.getConstructor(String.class,int.class) ; //获取指定参数类型的构造方法
Object obj = constructor.newInstance("a",11) ; //实例化对象
System.out.println(obj) ; //调用类对象中toString()方法
虽然程序代码本身允许开发者调用有参构造处理,但是所有使用反射的类中最好提供无参构造,这样实例化可以达到统一性。
3、反射调用普通方法
在进行反射处理时,在类提供有实例化对象的前提条件下,可以通过反射来获取类中的全部方法。
在Class类中提供的方法:
获取全部方法:public Method[] getMethods() throws SecurityException
获取指定方法:public Method getMethod(String name,Class<?>... parameterTypes) throws NoSuchMethodException,SecurityException
获取本类全部方法:public Method[] getDeclaredMethods() throws SecurityException
获取本类指定方法:public Method getDeclaredMethod(String name,Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
注意返回类型:Constructor类 和 Method类都是java.lang.reflect包中的,其信息的获取依靠的是类中提供toString()方法完成的,能够获取方法的修饰符、返回值类型、参数类型等信息。用户也可以进行自定义显示。
Method类中的一个重要方法:
反射调用类中的方法:public Object invoke(Object obj,Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
//获取指定类的Class对象
Class<?> cls = Class.forName("com.demo.Person") ;
//调用无参构造实例化
Object obj = cls.getDeclaredConstructor().newInstance() ;
//进行方法调用要获取方法名称,参数类型
String setMethodName = "setName" ; //方法名称
Method getMethod = cls.getDeclaredMethod(setMethodName,String.class) ;
//调用方法
String value = "a" ;
getMethod.invoke(obj,value) ; //等价于:Person对象.setName(value) ;
String getMethodName = "getName" ;
Method getMethod = cls.getDeclaredMethod(getMethodName) ; //getName()方法没有参数
System.out.println(getMethod.invoke(obj));
不会产生耦合,在复杂设计中使用会非常方便。
4、反射调用成员(Field)
获取本类全部成员:public Field[] getDeclaredFields() throws SecurityException
获取本类指定成员:public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException
获取父类全部成员:public Field[] getFields() throws SecurityException
获取父类指定成员:public Field getField(String name) throws NoSuchFieldException, SecurityException
//获取父类中的公共成员信息
Field fields [] = cls.getFields() ; //获取成员
for(Field fi : fields) {
System.out.println(fi) ;
}
//获取子类成员信息
Field fields [] = cls.getDeclaredFields() ; //获取成员
for(Field fi : fields) {
System.out.println(fi) ;
}
在Field类中更重要的三个方法:
设置成员属性:public void set(Object obj,Object value) throws IllegalArgumentException,IllegalAccessException
获取成员属性:public Object get(Object obj) throws IllegalArgumentException,IllegalAccessException
解除封装:(在设置成员属性值时,往往成员是私有的并不能直接设置或或获取,此时就需要解除封装,不仅可以解除属性封装还可以是构造方法、方法)public void setAccessible(boolean flag)
示例:
Class<?> cls = Class.forName("com.demo.Person") ;
Object obj = cls.getConstructor().newInstance() ; //实例化对象(才会分配成员空间)
Field nameField = cls.getDeclaredField("name") ; //获取成员对象name
nameField.setAccessible(true) ; //解除封装
nameField.set(obj,"a") ; //等价于Person对象.setName("a")
System.out.println(nameField.get(obj)) ;
实际上,对成员属性的操作,常用setter和getter方法,很少使用此种反射处理。
Field类中的一个常用方法:
获取成员类型:public Class<?> getType()
System.out.println(nameField.getType()) ; //class java.lang.String
System.out.println(nameField.getType().getName()) ; //java.lang.String
System.out.println(nameField.getType().getSimpleName()) ; //String
继承结构:
5、Unsafe类
反射是Java的一大特点,因此会有更加丰富的类设计形式。除了JVM本身支持的反射处理外,在Java中提供了一个sun.misc.Unsafe类,该类的主要特点是可以利用反射来获取对象,并且直接使用底层的C++来代替JVM执行,即可以绕过JVM的管理机制,同时项目之中也无法使用JVM的内存管理机制以及垃圾回收处理。
使用Unsafe类首先需要确认类中定义的构造方法与常量问题:
private Unsafe() {}
private static final Unsafe theUnsafe = new Unsafe() ;
在这个Unsafe类中没有提供static方法,如果想要获得这个类的对象,就必须利用反射机制来完成。
实现示例:
Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
field.setAccessible(true) ;
field.get(null) ; //static属性不需要传递实例化对象
在传统的开发之中,一个程序类必须通过实例化对象后才可以调用类中的普通方法,以单例设计模式为例(注意与传统饿汉式的区别):
import java.lang.reflect.Field ;
import sun.misc.Unsafe ;
public class BDemo {
public static void main(String[] args) throws Exception {
Field field = Unsafe.class.getDeclaredField("theUnsafe") ;
field.setAccessible(true) ;
Unsafe unsafeObject = (Unsafe)field.get(null) ;
//利用Unsafe类绕过JVM的管理机制,可以在没有实例化对象的情况下获取类实例化对象
Person instance = (Person)unsafeObject.allocateInstance(Person.class) ;
instance.println() ; //调用方法
}
}
class Person {
private Person() {
System.out.println("构造方法") ;
}
public void println() {
System.out.println("普通方法") ;
}
}
Unsafe类只能说为我们的开发提供了一些更加方便的处理机制,但是由于此种操作不受JVM的管理,所以并不建议使用,在设计单例设计模式时可以提及Unsafe类,以加深理解。