文章目录
Java反射机制
一、反射机制概述
反射概述:
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意一个方法和属性;
这种动态获取类的信息以及动态调用对象的方法的功能称为Java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对应的Class类型的对象,因为解剖使用的是Class类中的方法。
类的成员:
成员变量 Field
构造方法 Constructor
成员方法 Method
二、获取class文件对象的三种方式
a:Object类的getClass()方法
b:静态属性class
c:Class类中静态方法forName()
public class MyTest {
public static void main(String[] args) throws ClassNotFoundException {
//Object类的getClass()方法
Class<? extends MyTest> aClass = new MyTest().getClass();
// 静态属性class
Class<MyTest> myTestClass = MyTest.class;
//Class类中静态方法forName(),参数为全类名
Class<?> aClass1 = Class.forName("mydemo.MyTest");
//class文件对象只有一个,所以无论通过何种方式获取的class文件对象都是同一个
System.out.println(myTestClass==aClass&&aClass==aClass1);//true
}
}
三、通过反射获取构造方法并使用
//获取所有公共的构造方法的对象数组
public Constructor<?>[] getConstructors()
//获取所有的构造方法(包括私有的)的对象数组
public Constructor<?>[] getDeclaredConstructors()
//获取单个公共构造方法的对象
public Constructor<T> getConstructor(Class<?>... parameterTypes)
//获取单个构造方法的对象,包含私有的
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
T newInstance() //创建此 Class 对象所表示的类的一个新实例
public void setAccessible(boolean flag)//AccessibleObject的方法
//将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。
import java.lang.reflect.Constructor;
public class MyTest {
public static void main(String[] args) throws Exception {
Class<?> aClass = Class.forName("mydemo1.Student");
//获取所有公共的构造方法的对象数组
Constructor<?>[] constructors = aClass.getConstructors();
//获取所有的构造方法(包括私有的)的对象数组
Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
//获取单个私有构造方法的对象
Constructor<?> constructor = aClass.getDeclaredConstructor();
//取消访问检查
constructor.setAccessible(true);
//通过私有构造方法对象创建Student对象
Student student = (Student) constructor.newInstance();
System.out.println(student);
System.out.println("--------------------------------");
//获取公共有参构造方法对象
Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);
Student student1 = (Student) constructor1.newInstance("张三", 23);
System.out.println(student1);
}
}
class Student {
private Student() {
System.out.println("私有空参构造执行了");
}
public Student(String name,int age) {
System.out.println("有参构造执行了,"+name+"=="+age);
}
}
运行结果:
私有空参构造执行了
mydemo1.Student@4554617c
--------------------------------
有参构造执行了,张三==23
mydemo1.Student@74a14482
Process finished with exit code 0
四、通过反射获取成员变量并使用
//获取所有公共成员变量的对象,包含从父类继承过来的
public Field[] getFields()
//获取所有成员变量的对象,包含私有的,也包含从父类继承过来的
public Field[] getDeclaredFields()
public Field getField(String name)//获取单个公共成员变量的对象
public Field getDeclaredField(String name)//获取单个成员变量的对象
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class MyTest {
public static void main(String[] args) throws Exception{
//创建Student对象
Class<?> aClass = Class.forName("mydemo2.Student");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object stu = declaredConstructor.newInstance();
//获取成员变量对象,并给成员变量赋值
Field name = aClass.getField("name");//参数为字段名称
name.set(stu,"张三");//参1为字段所属对象,参2为要赋的值
Field age = aClass.getDeclaredField("age");
age.set(stu,23);
Field x = aClass.getDeclaredField("x");
x.setAccessible(true);//取消访问检查
x.set(stu,3.323);
System.out.println(name.get(stu)+"=="+age.get(stu)+"=="+x.get(stu));
//张三==23==3.323
}
}
class Student{
public String name;
int age;
private double x;
private Student(){}
}
五、通过反射获取成员方法并使用
//获取所有公共成员方法的对象数组,包含从父类继承过来的公共方法
public Method[] getMethods()
public Method[] getDeclaredMethods()//获取自己所有成员方法的对象数组
//获取单个公共成员方法的对象
public Method getMethod(String name,Class<?>... parameterTypes)
//获取单个成员方法的对象,包括私有的
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
//参数1: 方法名称 参数2:方法行参的class 对象
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MyTest {
public static void main(String[] args)throws Exception{
//创建MyClass对象
Class<?> aClass = Class.forName("mydemo3.MyClass");
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
//获取单个公共成员方法的对象
Method show = aClass.getMethod("show");
show.invoke(o);//执行此方法,参数为此方法所属对象
//获取私有的成员方法对象
Method show1 = aClass.getDeclaredMethod("show", int.class);
show1.setAccessible(true);//取消权限检查
Object invoke = show1.invoke(o, 22);
System.out.println(invoke);//返回值
Method haha = aClass.getDeclaredMethod("test", String.class, int.class);
haha.setAccessible(true);
Object invoke1 = haha.invoke(o, "我是", 777);
System.out.println(invoke1);
}
}
class MyClass{
private MyClass() {
System.out.println("私有构造方法执行了");
}
public void show(){
System.out.println("无参公共的show方法执行了");
}
private String show(int num){
System.out.println("有参私有的show方法执行了");
return "show:"+num;
}
private String test(String str,int num){
System.out.println("有参私有的test方法执行了");
return "test:"+str+num;
}
}
运行结果:
私有构造方法执行了
无参公共的show方法执行了
有参私有的show方法执行了
show:22
有参私有的test方法执行了
test:我是777
Process finished with exit code 0
六、通过反射越过泛型检查
//往ArrayList<Integer>里添加String类型元素
//原理:泛型只在编译期有效,运行期就会擦除,而反射机制是在运行状态中
import java.lang.reflect.Method;
import java.util.ArrayList;
public class MyTest {
public static void main(String[] args) throws Exception{
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
Class<? extends ArrayList> aClass = list.getClass();
Method add = aClass.getDeclaredMethod("add", Object.class);
add.setAccessible(true);
add.invoke(list,"abc");
System.out.println(list);//[100, abc]
}
}
七、通过反射运行配置文件内容
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
public class MyTest1 {
public static void main(String[] args) throws Exception {
//要使用某个类的某个方法,只需要修改配置文件即可
Properties properties = new Properties();
//关联配置文件
properties.load(new FileReader("configurationFile.properties"));
//获取配置文件中指定类的Class对象
Class<?> aClass = Class.forName((String) properties.get("className"));
//获取构造方法对象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
declaredConstructor.setAccessible(true);//取消安全检查
//创建配置文件中指定类的对象
Object o = declaredConstructor.newInstance();
//获取配置文件中指定方法的对象
Method mathod = aClass.getDeclaredMethod((String) properties.get("mathodName"));
//取消安全检查
mathod.setAccessible(true);
mathod.invoke(o);//执行方法
}
}
class Dog {
private Dog() {
}
public void eat() {
System.out.println("狗吃骨头");
}
public void sleep() {
System.out.println("狗晚上睡觉");
}
}
class Cat {
private Cat() {
}
public void eat() {
System.out.println("猫吃鱼");
}
public void sleep() {
System.out.println("猫白天睡觉");
}
}
配置文件内容:
className=mydemo4.Dog
mathodName=sleep
对应运行结果:
狗晚上睡觉
配置文件内容:
className=mydemo4.Cat
mathodName=eat
对应运行结果:
猫吃鱼