反射技术:
动态的加载和获取一个类和类中的内容(成员)
好处:极大的提高了程序的扩展性。
对于框架或者服务器Tomcat,底层都用了这种反射技术。
使用反射技术:
第一步:就是动态获取类文件对象,需要使用对类文件进行描述的类Class。
类文件对象的类型就是Class类型。
如何去获取一个字节码文件对象呢?
三种方式:
1,通过每一个对象都具备的object类中的getClass()方法获取;
2,通过每一种数据类型都具备的一个静态的class属性。
3,通过Class类中的forName方法。这种方式最常用。扩展性最强 。
Class类就是反射技术主要应用类之一,有了该类就可以动态获取字节码文件对象。
只要获取了字节码文件对象,获取字节码文件中的内容就直接使用该Class对象的方法就哦了。
这个也可以简单理解为时对类文件的解剖。
* 获取字节码文件对象三种方式:
* 1,每一个对象在内存中建立,都有自己对应字节码文件对象。
* 可以通过Object中的getClass方法获取该对象的字节码文件对象。
* 这种方式必须要明确具体类名称,并建立该类的对象,才可以通过getClass获取字节码文件对象。有点麻烦。
*
public static void getClass_1(){
Person p1 = new Person();
Person p2 = new Person();
Class clazz1 = p1.getClass();
Class clazz2 = p2.getClass();
System.out.println(clazz1==clazz2);
}
* 2,每一个数据类型都有一个静态的属性class。通过该class属性即可获取该类型的Class对象。
* 这种方式相对简单,但是还是需要使用具体类来完成该类字节码文件对象获取。
*
public static void getClass_2(){
Class clazz = Person.class;
Class c = int.class;
* 3,通过Class类中的forName方法,通过类字符串名称即可获取该类的字节码文件对象。
* 这种方式扩展性更好一些,因为只要知道名称即可forName会自动去找与该名称相同的字节码文件.
类 Class<T>
java.lang.Class<T>
类型参数:
T - 由此 Class 对象建模的类的类型。例如,String.class 的类型是 Class<String>。如果将被建模的类未知,则使用 Class<?>。
Class 类的实例表示正在运行的 Java 应用程序中的类和接口
Class 没有公共构造方法。Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass 方法自动构造的。
static Class<?> |
Class clazz = Class.forName("cn.itcast.bean.Person");
里面传的参数是类名的字符串形式,在写的时候一定要加上包名,不然会现:ClassNotFoundException类找不到异常。
既然已经拿到了该类的字节码文件对象,就需要对该类中的内容进行获取;
而一个类中的内容无非就是:
1,字段。 2,方法。 3,构造函数。
一, 获取方法:
1,获取的是所有方法的数组;
Method[] | getMethods() |
Method[] | getDeclaredMethods() |
public static void getFunctions() throws ClassNotFoundException{
//获取指定名称的字节码文件对象。
Class clazz = Class.forName("cn.itcast.bean.Person");
//通过字节码对象获取字节码中的内容-函数。
Method[] methods = clazz.getMethods();//返回的是类中的公共方法,包括从object类中继承的方法。
methods = clazz.getDeclaredMethods();//获取的是本类中的方法数组,包含私有的方法。
//遍历方法数组。
for(Method m : methods){
System.out.println(m);
}
}
二, 获取指定的方法,并使其能运行:
getMethod(String name, Class<?>... parameterTypes) |
name 参数是一个 String,用于指定所需方法的简称。parameterTypes 参数是按声明顺序标识该方法形参类型的 Class 对象的一个数组。如果 parameterTypes 为 null,则按空数组处理。
参数:
name - 方法名
parameterTypes - 参数列表
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show", null);
newInstance() |
Object obj = clazz.newInstance();创建了一个该类的对象相当于。
这据话就相当于Person p=new Person();
在反射中,如果要让一个反射到的非静态方法执行,两个要素,一个是该方法所属的对象,二是,具体的参数值。
方法对象如何运行,方法对象自己最清楚,应该到Method对象中的去找方法。
这个方法需要传入一个被调用方法所属的对象。
如何获取一个指定的字节码文件对象创建的对象呢?当是通过字节码文件对象来完成
类 Method
java.lang.reflect.AccessibleObject
Method 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。所反映的方法可能是类方法或实例方法(包括抽象方法)。
Method 允许在匹配要调用的实参与底层方法的形参时进行扩展转换;但如果要进行收缩转换,则会抛出 IllegalArgumentException。
invoke(Object obj, Object... args) |
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show", null);
Object obj = clazz.newInstance();
method.invoke(obj, null);
三,获取一个静态方法。
public static void getStaticFunciton() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show3", null);
method.invoke(null, null);由于静态方法不需要对象调用也行,所以在传入对象时就传入null就可以运行了。
四,暴力反射私有方法:
getDeclaredMethod(String name, Class<?>... parameterTypes) |
此方法可以根据所传的参数获取指定的私有方法。
如果要运行此私有方法,就需要用到Method对象父类中的setAccessible 方法来取消它的私有权限,对它进行暴力访问。
void | setAccessible(boolean flag) |
将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
public static void getPrivateFunction() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getDeclaredMethod("show2", null);
method.setAccessible(true);//取消检查访问权限。暴力访问。
Object obj = clazz.newInstance();
method.invoke(obj, null);
}
五,获取一个带有参数的方法。
public static void getParamterFunction() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getDeclaredMethod("show4",int.class,String.class );
Object obj = clazz.newInstance();
method.invoke(obj, 31,"hahaha");
}
六,获取构造函数
如何进行指定类中的实例化呢?
* 通常使用的是newInstance()方法完成,它会调用类中空参数构造函数。
* 但是如果类中没有空参数构造函数,或者需要通过指定的构造函数实例化。怎么办呢?
*
* 1,必须先获取到指定的构造函数对象。
* 2,通过指定的构造函数对象进行指定的类的对象的初始化。
getConstructor(Class<?>... parameterTypes) | |
Constructor<?>[] | getConstructors() |
类 Constructor<T>
java.lang.reflect.AccessibleObject
java.lang.reflect.Constructor<T>
类型参数:
T - 在其中声明构造方法的类。
newInstance(Object... initargs) |
参数:
initargs - 将作为变量传递给构造方法调用的对象数组;基本类型的值被包装在适当类型的包装器对象(如 Float 中的 float)中。
返回:
通过调用此对象表示的构造方法来创建的新对象
public static void getConstructor() throws Exception{
Class clazz = Class.forName("cn.itcast.bean.Person");
//获取了到指定的构造器对象。
Constructor constructor = clazz.getConstructor(String.class,int.class);
//可以通过指定的构造器对象进行初始化。
Object obj = constructor.newInstance("lisi",39);
Method method = clazz.getMethod("show5", null);
method.invoke(obj, null);
}