java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法。对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取信息以及动态调用对象的方法的功能成为java语言的反射机制。(动态获取类中的信息,就是java反射,也可以称为对类的解剖)
想要对字节码文件进行解剖,就必须要有字节码文件对象。下面介绍三种方法获取字节码文件对象:
- 使用Object类中的getClass()方法:必须明确具体的类并创建对象。(比较麻烦)
public static void getClassObject_1() {
Person p = new Person();
Class clazz = p.getClass();
Person p1 = new Person();
Class clazz1 = p.getClass();
System.out.println(p == p1);//false
System.out.println(clazz == clazz1);//true
}
- 使用类中的静态属性.class来获取类对象:需要知道类名,并调用类中的静态成员。
public static void getClassObject_2() {
Class clazz = Person.class;
Class clazz1 = Person.class;
System.out.println(clazz == clazz1);//true
}
- 只要通过给定类的字符串名就可以获取该类:使用class类中的方法完成,forName()方法。更方便。
public static void getClassObject_3() throws ClassNotFoundException {
//String className = "Person";//报错,类名错误,类名需要完整,包括所有的包,java.lang.ClassNotFoundException: Person
String className = "cn.itcast.bean.Person";
Class clazz = Class.forName(className);
System.out.println(clazz);
}
- 反射机制的使用实例:
1、产生该类的对象
public static void createNewObject()
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
/*
* 早期:new的时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,
* 并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象。
*/
//cn.itcast.bean.Person p = new cn.itcast.bean.Person();
//现在:
String name = "cn.itcast.bean.Person";
//找寻该名称类文件,并加载进内存,并产生class对象。
Class clazz = Class.forName(name);
//如何产生该类的对象呢?
Object obj = clazz.newInstance();//如果类中无空参构造函数,则会报出异常,此方法只适用于类中有空参构造函数的情况。
}
public static void createNewObject_2() throws ClassNotFoundException, Exception, SecurityException {
// cn.itcast.bean.Person p = new cn.itcast.bean.Person("xiaoqiang", 38);
/*
* 当获取指定名称对应类中的所体现的对象时,
* 对该对象初始化不使用空参数构造该怎么办?
* 既然是通过指定的构造函数进行对象的初始化,
* 所以应该先获取到该构造函数,通过字节码文件对象即可完成。
* 该方法是:getConstructor(paramterTypes);
*
*/
String name = "cn.itcast.bean.Person";
//找寻该名称类文件,并加载进内存,并产生class对象。
Class clazz = Class.forName(name);
//获取到了指定的构造函数对象
Constructor constructor = clazz.getConstructor(String.class, int.class);//String.class和int.class表示类中Sting和int型的字节码文件
//通过该构造器对象的newInstance方法进行对象的初始化。
Object obj = constructor.newInstance("xiaoming", 28);
}
2、获取字节码文件中的字段
public static void getFieldDemo() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
// Field field = clazz.getField("name");//只能获取公有的字段
Field field = clazz.getDeclaredField("age");//凡是加declared的方法都能够获取类中所有的成员。包括私有成员。
System.out.println(field);
//对私有字段的访问取消权限检查。暴力访问
field.setAccessible(true);
Object obj = clazz.newInstance();
field.set(obj, 89);
Object o = field.get(obj);
System.out.println(o);
}
3、获取类的方法
//获取有参数的方法并调用
public static void getMethodDemo_3() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("paramMethod", String.class, int.class);
Object obj = clazz.newInstance();
method.invoke(obj, "xioqiang",23);
}
//获取单个方法并调用方法
public static void getMethodDemo_2() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
Method method = clazz.getMethod("show", null);//获取方法需要传递方法名称和参数,获取空参数一般方法。
//Object obj = clazz.newInstance();
Constructor constructor = clazz.getConstructor(String.class, int.class);
Object obj = constructor.newInstance("xiaoming",23);
method.invoke(obj, null);
}
// 获取指定class中的所有公共函数
public static void getMethodDemo() throws Exception {
Class clazz = Class.forName("cn.itcast.bean.Person");
//Object obj = clazz.newInstance();
//Method[] methods = clazz.getMethods();//获取的都是public方法,包含父类object中的方法
Method[] methods = clazz.getDeclaredMethods();//可以获取任何权限的方法。只获取本来中所有方法,包含私有。
for(Method method : methods){
System.out.println(method);
}
}