Java反射机制

mac2024-08-23  181

概述

 Java反射机制指的是在Java程序运行状态中,对于任何一个类,都可以获得这个类的所有属性和方法;对于给定的一个对象,都能够调用它的任意一个属性和方法。这种动态获取类的内容以及动态调用对象的方法称为反射机制。

意义

(1)反射机制极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力。 (2)通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类。 (3)使用反射机制能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法。 (4)反射机制是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中。

反射机制的相关类

与Java反射相关的类如下:

与Java反射相关的类如下:

类名用途Class类代表类的实体,在运行的Java应用程序中表示类和接口Field类代表类的成员变量(成员变量也称为类的属性)Method类代表类的方法Constructor类代表类的构造方法

Class类

获得类相关的方法 方法用途asSubclass(Class<U> clazz)把传递的类的对象转换成代表其子类的对象Cast把对象转换成代表类或是接口的对象getClassLoader()获得类的加载器getClasses()返回一个数组,数组中包含该类中所有公共类和接口类的对象getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象forName(String className)根据类名返回类的对象getName()获得类的完整路径名字newInstance()创建类的实例getPackage()获得类的包getSimpleName()获得类的名字getSuperclass()获得当前类继承的父类的名字getInterfaces()获得当前类实现的类或是接口 获得类中属性相关的方法 方法用途getField(String name)获得某个公有的属性对象getFields()获得所有公有的属性对象getDeclaredField(String name)获得某个属性对象getDeclaredFields()获得所有属性对象 获得类中注解相关的方法 方法用途getAnnotation(Class<A> annotationClass)返回该类中与参数类型匹配的公有注解对象getAnnotations()返回该类所有的公有注解对象getDeclaredAnnotation(Class<A> annotationClass)返回该类中与参数类型匹配的所有注解对象getDeclaredAnnotations()返回该类所有的注解对象 获得类中构造器相关的方法 方法用途getConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法getConstructors()获得该类的所有公有构造方法getDeclaredConstructor(Class...<?> parameterTypes)获得该类中与参数类型匹配的构造方法getDeclaredConstructors()获得该类所有构造方法 获得类中方法相关的方法 方法用途getMethod(String name, Class...<?> parameterTypes)获得该类某个公有的方法getMethods()获得该类所有公有的方法getDeclaredMethod(String name, Class...<?> parameterTypes)获得该类某个方法getDeclaredMethods()获得该类所有方法 类中其他重要的方法 方法用途isAnnotation()如果是注解类型则返回trueisAnnotationPresent(Class<? extends Annotation> annotationClass)如果是指定类型注解类型则返回trueisAnonymousClass()如果是匿名类则返回trueisArray()如果是一个数组类则返回trueisEnum()如果是枚举类则返回trueisInstance(Object obj)如果obj是该类的实例则返回trueisInterface()如果是接口类则返回trueisLocalClass()如果是局部类则返回trueisMemberClass()如果是内部类则返回true

Field类

Filed代表类的成员变量(成员变量也称为类的属性)。

方法用途equals(Object obj)属性与obj相等则返回trueget(Object obj)获得obj中对应的属性值set(Object obj, Object value)设置obj中对应属性值

Method类

Method代表类的方法。

方法用途invoke(Object obj, Object... args)传递object对象及参数调用该对象对应的方法

Constructor类

Constructor代表类的构造方法。

方法用途newInstance(Object... initargs)根据传递的参数创建类的对象

示例

目录结构图

Student.class

package com.lzh.model; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import lombok.ToString; /** * @author lzh * create 2019-10-27-10:38 */ public class Student { private String name; private Integer age; public Student() { } private Student(String name){ this.name = name; } public Student(String name, Integer age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }

 Employee.class

package com.lzh.model; /** * @author lzh * create 2019-10-27-16:32 */ public class Employee { public void show(){ System.out.println("is show()"); } }

Employee2

package com.lzh.model; /** * @author lzh * create 2019-10-27-16:32 */ public class Employee2 { public void show2(){ System.out.println("is show2()"); } }

Dog.class

package com.lzh.model; /** * @author lzh * create 2019-10-27-10:36 */ public class Dog { private String name; private Integer age; public String type; public Integer height; private Dog() { } private Dog(String name, Integer height) { this.name = name; this.height = height; } public Dog(String name, String type, Integer height, Integer age) { this.name = name; this.type = type; this.height = height; this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + ", type='" + type + '\'' + ", height=" + height + '}'; } }

Teacher.class

package com.lzh.model; /** * @author lzh * create 2019-10-27-16:14 */ public class Teacher { public void show1(String s) { System.out.println("调用了:公有的,String参数的show1(): s = " + s); } protected void show2() { System.out.println("调用了:受保护的,无参的show2()"); } void show3() { System.out.println("调用了:默认的,无参的show3()"); } private String show4(int age) { System.out.println("调用了,私有的,并且有返回值的,int参数的show4(): age = " + age); return "abcd"; } }

测试类,反射可获取私有属性和私有方法并进行操作

package com.lzh.classreflect; import com.lzh.model.Dog; import com.lzh.model.Student; import org.junit.Test; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author lzh * create 2019-10-27-10:39 */ public class TestClass { @Test public void getClassTest() { //1、获得Class:主要有三种方法: //第一种方式获取Class对象 Student student = new Student(); Class stuClass1 = student.getClass(); System.out.println(stuClass1.getName()); //第二种方式获取Class对象 Class stuClass2 = Student.class; System.out.println(stuClass2.getName()); System.out.println(stuClass1 == stuClass2); //第三种方式获取Class对象 try { Class stuClass3 = Class.forName("com.lzh.model.Student");//注意此字符串必须是真实路径,就是带包名的类路径,包名.类名 System.out.println(stuClass3 == stuClass2);//判断三种方式是否获取的是同一个Class对象 } catch (ClassNotFoundException e) { e.printStackTrace(); } } @Test public void isInstanceTest(){ Student student = new Student(); //判断是否为某个类 System.out.println(student instanceof Student); } @Test public void newObjectTest() throws IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException { //创建实例:通过反射来生成对象主要有两种方法 //1.使用Class对象的newInstance()方法来创建Class对象对应类的实例。 Class c = Student.class; Object stu1 = c.newInstance(); //2.先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建对象,这种方法可以用指定的构造器构造类的实例。 Class<?> stu2 = Student.class; //通过Class对象获取指定的Constructor构造器对象 Constructor<?> constructor = stu2.getConstructor(String.class, Integer.class); Object raicho = constructor.newInstance("raicho", 21); System.out.println(raicho); } @Test public void getConstructorTest() throws IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException { Class<?> stu = Student.class; //所有"公有的"构造方法 Constructor<?> constructor = stu.getConstructor(String.class, Integer.class); Object stu1 = constructor.newInstance("raicho_one", 21); System.out.println(stu1); System.out.println("----------------------------------"); //获取所有的构造方法(包括私有、受保护、默认、公有) Constructor<?>[] constructors=stu.getConstructors(); for (Constructor<?> constructor1 : constructors) { System.out.println(constructor1); } //根据构造器创建实例: Object obj = constructors[0].newInstance("小王",21); System.out.println(obj); System.out.println("----------------------------------"); //获取"某个构造方法"可以是私有的,或受保护、默认、公有; Constructor<?> declaredConstructor = stu.getDeclaredConstructor(String.class); //System.out.println("declaredConstructor="+declaredConstructor); //设置越过安全检查 declaredConstructor.setAccessible(true); Object stu2 = declaredConstructor.newInstance("raicho"); System.out.println(stu2); System.out.println("获取所有构造器,包括私有"); Constructor<?>[] declaredConstructors = stu.getDeclaredConstructors(); for (Constructor<?> declaredConstructor1 : declaredConstructors) { System.out.println(declaredConstructor1); } System.out.println("----------------------------------"); } @Test public void getsetPropertyTest() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException { Class<?> dogClass = Class.forName("com.lzh.model.Dog"); System.out.println("************获取所有公有的字段********************"); Field[] fields = dogClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("************获取所有的字段(包括私有、受保护、默认的)********************"); Field[] declaredFields = dogClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("*************设置私有属性值***********************************"); Constructor<?> declaredConstructor = dogClass.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Dog dog1 = (Dog) declaredConstructor.newInstance(); System.out.println(dog1); //dog1.setName("阿拉斯"); Field field = Dog.class.getDeclaredField("name"); field.setAccessible(true); field.set(dog1,"阿拉斯"); System.out.println(dog1); } @Test public void method() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { Class<?> teacherClass = Class.forName("com.lzh.model.Teacher"); System.out.println("***************获取所有的”公有“方法*******************"); Method[] methods = teacherClass.getMethods(); for (Method method : methods) { System.out.println(method); } System.out.println("***************获取所有的方法,包括私有的*******************"); Method[] declaredMethods = teacherClass.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } System.out.println("***************获取私有的show4()方法******************"); Method show4 = teacherClass.getDeclaredMethod("show4", int.class); System.out.println(show4); Object obj = teacherClass.getConstructor().newInstance(); //越过安全检查 show4.setAccessible(true); Object result = show4.invoke(obj, 21); System.out.println("返回值:"+result); } }

通过反射越过集合泛型检查,为集合添加不同类型的数据

package com.lzh.collectionreflect; import org.junit.Test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * @author lzh * create 2019-10-27-17:15 */ public class CollectionTest { @Test public void collectionTest() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //通过反射越过泛型检查 //有一个String泛型的集合,向这个集合中添加一个Integer类型的值 List<String> list = new ArrayList<String>(); list.add("aaa"); list.add("bbb"); //list.add(100); //报错 //获得集合Class对象 Class listClass = list.getClass(); //获得add()方法 Method add = listClass.getMethod("add", Object.class); //调用add()方法 add.invoke(list,100); for (Object s : list) { System.out.println(s); } } }

创建pro.properties文件,通过反射

className = com.lzh.model.Employee2 methodName = show2

加载配置文件,通过反射机制创建对象,在不修改代码的情况下动态修改配置文件创建新对象

package com.lzh.filereflect; import org.junit.Test; import java.io.*; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; import java.util.ResourceBundle; /** * @author lzh * create 2019-10-27-16:30 */ public class FileTest { @Test public void fileTest() throws IOException, ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { //1.通过反射获取Class对象 Class<?> employeeclass = Class.forName(getValue("className")); // String className = getValue("className"); // System.out.println(className); //2.获取show()方法 Method method = employeeclass.getMethod(getValue("methodName")); //3.调用show()方法 method.invoke(employeeclass.getConstructor().newInstance()); //当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.properties的文件内容就可以了。代码就一点不用改动。 } public String getValue(String key) throws IOException { Properties properties = new Properties(); // 使用ClassLoader加载properties配置文件生成对应的输入流 InputStream in = new FileInputStream("F:\\idea2018WorkSpace\\reflect-mechanism\\src\\main\\java\\com\\lzh\\filereflect\\pro.properties"); // 使用properties对象加载输入流 properties.load(in); //获取key对应的value值 String property = properties.getProperty(key); return property; } }

代码

github代码:https://github.com/LZHDonald/reflect-mechanism

参考

百度百科:https://baike.baidu.com/item/ JAVA%E5%8F%8D%E5%B0%84%E6%9C%BA%E5%88%B6/6015990?fr=aladdin

简书:https://www.jianshu.com/p/9be58ee20dee

最新回复(0)