反射的概念
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
功能
Java反射机制主要提供了以下功能:
1. 在运行时判断任意一个对象所属的类;
2. 在运行时构造任意一个类的对象;
3. 在运行时判断任意一个类所具有的成员变量和方法;
4. 在运行时调用任意一个对象的方法;
5. 生成动态代理。
理解反射的概念
反射就是把Java类中的各种成分映射成相应的Java类。
例如:众多的人用一个Person类来表示,那么众多的Java类就用一个Class类来表示。
Person 类代表人,它的实例对象就是张三,李四这样一个个具体的人;
Class类代表Java类,它的各个实例对象对应的就是各个类在内存中的字节码,例如:Person类的字节码,ArrayList类的字节码等等。
Class类用于表示.class文件,是所有加载进内存的字节码对象的父类。所以可以通过Class得到运行时的类。
如何得到某个class文件对应的class对象呢?
方法有3种:
1)类名.class 例如,Person.class。
2)对象.getClass() 例如,new Data().getClass()。
3)Class.forName("包名.类名"); 例如,Class.forName("java.lang.String");
package com.laobi.day28;
public class ReflectDemo {
/**
* java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法
* 对于任意一个对象,都能够调用它的任意一个方法和属性
* 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
*
* 动态获取类中信息,就是java反射
* 可以理解为对类对解剖
*
* 要想要对字节码文件进行解剖,必须要有字节码文件对象。
* 如何获取字节码文件对象呢?
* @throws ClassNotFoundException
*
*/
public static void main(String[] args) throws ClassNotFoundException {
getClassObject_3();
}
/*
* 方式三:
* 只要通过给定的类的字符串名称就可以获取该类,更为扩展
* 可是用class类中的方法完成
* 该方法就是forName
* 这种方式只要有名称即可,更为方便,扩展性更强。
*/
private static void getClassObject_3() throws ClassNotFoundException {
String className = "com.laobi.day28.Person";
Class c = Class.forName(className);
System.out.println(c);
}
/*
* 方式二:
* 任何数据类型都具备一个静态的属性.class来获取其对应的Class对象
* 相对简单,但是还要明确用到类中的静态成员
* 还是不够扩展
*/
private static void getClassObject_2() {
Class class1 = Person.class;
Class class2 = Person.class;
System.out.println(class1==class2);
}
/*
* 方式一:
* 获取字节码对象对方式:
* 1、Object类中对getClass方法
* 想要用这种方式,必须要明确具体的类,并创建对象。
*/
public static void getClassObject_1(){
Person p = new Person();
Class class1 = p.getClass();
Person p1 = new Person();
Class class2 = p1.getClass();
System.out.println(class1==class2);
}
}
注意:字节码文件是唯一的,所以无论怎么获取,都是同一份字节码文件。
九个预定义Class实例对象(八大原始类型+void)
Class 类的实例表示正在运行的 Java 应用程序中的类和接口。枚举是一种类,注释是一种接口。
每个数组属于被映射为 Class 对象的一个类,所有具有相同元素类型和维数的数组都共享该Class 对象。
基本的 Java 类型(boolean、byte、char、short、int、long、float 和 double)和关键字 void也表示为 Class 对象。
反射的基本步骤:
1、获得Class对象,就是获取到指定的名称的字节码文件对象。
2、实例化对象,获得类的属性、方法或构造函数。
3、访问属性、调用方法、调用构造函数创建对象。
package com.laobi.day28;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class ReflectDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
createNewObject_2();
}
private static void createNewObject_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
// com.laobi.day28.Person p = new com.laobi.day28.Person("旺财",29);
/*
* 当获取指定名称对应类中的所体现的对象时,
* 而该对象初始化不使用空参数构造该怎么办呢?
* 既然是通过指定的构造函数进行对象的初始化,
* 所以应该先获取到该构造函数。通过字节码文件对象即可完成。
* 该方法是:getConstructor(paramterTypes);
*/
String name = "com.laobi.day28.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象
Class class1 = Class.forName(name);
//获取到了指定到构造函数对象
Constructor constructor = class1.getConstructor(String.class,int.class);
//通过该构造器对象的newInstance方法进行对象的初始化
Object obj = constructor.newInstance("小强",16);
}
public static void createNewObject() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
//早期:new时候,先根据被new的类的名称找寻该类的字节码文件,并加载进内存,并创建该字节码文件对象,并接着创建该字节文件的对应的Person对象。
// com.laobi.day28.Person p = new com.laobi.day28.Person();
//现在:
String name = "com.laobi.day28.Person";
//找寻该名称类文件,并加载进内存,并产生Class对象
Class class1 = Class.forName(name);
//如何产生该类的对象呢?
Object obj = class1.newInstance();
}
}
构造方法的反射应用(Coustructor类)
Constructor类的实例对象代表类的一个构造方法。
反射公共,私有和保护的构造方法:
反射公共的需要的方法是:getConstructor();
反射私有的需要的方法是:getDeclaredConstructor();
Constructor对象代表一个构造方法,Constructor对象有的方法:得到构造方法名字,得到所属于的类,产生实例对象。
暴力反射
反射里的Constructor,Field,Method三个类都有一个getDeclaredXxx方法,可以不受权限控制的获取类的构造函数,
字段,方法,如果想要私有构造函数创建对象,字段赋值,方法调用的话,会自动的访问类的isAccessable,默认的是false,
所以,要想访问类中的私有成员的时候,就要调用setAccessable方法,将其改为true,
这样,就可以对类中的私有成员进行操作了.
package com.laobi.day28;
import java.lang.reflect.Field;
public class ReflectDemo3 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
getFieldDemo();
}
private static void getFieldDemo() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException {
Class class1 = Class.forName("com.laobi.day28.Person");
Field field =null;// class1.getField("age");//获取公有的
field = class1.getDeclaredField("age");//只获取本类的,包含私有的
//对私有字段的访问取消权限检查.也称暴力访问
field.setAccessible(true);
Object obj = class1.newInstance();
field.set(obj,89);
Object o = field.get(obj);
System.out.println(o);
}
}
成员方法的反射(Method类)
Method类代表某个类中的一个成员方法
得到类中的某一个方法:
例子:Method charAt =Class.forName("java.lang.String").getMethod("charAt",int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式:System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?
说明该Method对象对应的是一个静态方法!
package com.laobi.day28;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectDemo4 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
getMethodDemo_3();
}
public static void getMethodDemo_3() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class class1 = Class.forName("com.laobi.day28.Person");
Method method = class1.getMethod("paramMethod",String.class,int.class);// 获取空参数一般方法
Object obj = class1.newInstance();
method.invoke(obj, "小强",14);
}
public static void getMethodDemo_2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
Class class1 = Class.forName("com.laobi.day28.Person");
Method method = class1.getMethod("show", null);//获取空参数一般方法
// Object obj = class1.newInstance();
Constructor constructor = class1.getConstructor(String.class,int.class);
Object obj = constructor.newInstance("旺财",24);
method.invoke(obj, null);
}
/*
* 获取指定Class中的所以公有方法
*/
public static void getMethodDemo() throws ClassNotFoundException {
Class class1 = Class.forName("com.laobi.day28.Person");
Method[] methods = class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
}
}