之前找工作时,学习过Java的反射,当时的印象如下:
- Field、Method、Constructor的获取方法都是通的
- 对私有成员的访问,一定要通过
setAccessible(true)
开启权限 - 反射的作用这么强大,但自己很难体会
最近想重新学习Java反射,于是先从反射的使用开始,重新整理了Java反射的相关知识(停留在反射的使用上)。
相关代码:
-
ClassTest类
package com.lucy; public class ClassTest { // 创建不同修饰符的属性 public static final String NAME = "ClassTest"; public String publicValue; public int age = 21; protected String protectedValue; String defaultValue; private String privateValue; // 创建不同修饰符的构造函数 public ClassTest() { } public ClassTest(String protectedValue, String defaultValue, String privateValue) { this.publicValue = "public constructor"; this.protectedValue = protectedValue; this.defaultValue = defaultValue; this.privateValue = privateValue; System.out.println("public constructor"); } protected ClassTest(String publicValue, String protectedValue, String defaultValue, String privateValue) { this.publicValue = publicValue; this.protectedValue = "protected constructor"; this.defaultValue = defaultValue; this.privateValue = privateValue; System.out.println("protected constructor"); } private ClassTest(String protectedValue, String defaultValue) { this.publicValue = "public"; this.protectedValue = protectedValue; this.defaultValue = defaultValue; this.privateValue = "private constructor"; System.out.println("private constructor"); } ClassTest(String defaultValue) { this.publicValue = "public"; this.protectedValue = "protected"; this.defaultValue = defaultValue; this.privateValue = "private"; System.out.println("default constructor"); } // 创建不同修饰符的方法 public void sayHello() { System.out.println("无参数的public方法: Hello world"); } public void sayHello(String msg) { System.out.println("带参数的public方法: " + "Hello " + msg); } protected void sayHello(String name, int age) { System.out.println("带参数的protected方法: " + "Hello, I'm " + name + ", " + age + "yeas old."); } void sayHello(int age) { System.out.println("带参数的default方法: " + "Hello, " + age); } private void sayHello(int age, int height) { System.out.println("带参数的private方法:" + "I'm " + age + " years old, " + height + " cm tall"); } }
-
反射的使用:
package com.lucy; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Main { public static void main(String[] args) { getClassTest(); getFieldTest(); getMethodTest(); getConstructorTest(); } /** * 获取类的class对象 * * @param * @return void * @author sunrise * @date 2021/1/2 18:06 **/ public static void getClassTest() { // 通过类名获取class对象 Class clazz1 = ClassTest.class; // 通过对象名获取class对象 ClassTest classTest = new ClassTest(); Class clazz2 = classTest.getClass(); // 通过类的完全限定名获取class对象 try { Class clazz3 = Class.forName("com.lucy.ClassTest"); } catch (ClassNotFoundException e) { e.printStackTrace(); } // 通过class对象进行类的实例化,只能调用默认构造函数 System.out.println("==================================\n" + "通过class对象实例化类"); try { ClassTest object = (ClassTest) clazz1.newInstance(); object.sayHello(24); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } /** * 获取类的属性 * * @param * @return void * @author sunrise * @date 2021/1/2 17:05 **/ public static void getFieldTest() { // 先要获取类的class对象 Class clazz = ClassTest.class; // 获取类的所有公有属性 Field[] fields1 = clazz.getFields(); System.out.println("============================\n" + "获取类的所有公有属性"); for (Field field : fields1) { System.out.println(field.toString()); } // 获取类的所有属性 Field[] fields2 = clazz.getDeclaredFields(); System.out.println("============================\n" + "获取类的所有属性"); for (Field field : fields2) { System.out.println(field.toGenericString()); } // 获取指定名称的类属性,会抛出NoSuchFieldException try { // 获取类的指定名称的公有属性 System.out.println("============================\n" + "获取类的指定名称的公有属性"); Field field1 = clazz.getField("publicValue"); System.out.println(field1.toString()); // 获取类的指定名称的非公有属性 System.out.println("============================\n" + "获取类的指定名称的非公有属性"); Field field2 = clazz.getDeclaredField("protectedValue"); System.out.println(field2.toString()); Field field3 = clazz.getDeclaredField("privateValue"); System.out.println(field3.toString()); } catch (NoSuchFieldException e) { e.printStackTrace(); } // get/set属性值 try { System.out.println("============================\n" + "获取属性的值"); // 1. 先进行类的实例化 ClassTest classTestObject = new ClassTest("protected", "default", "private"); // 2. 通过类的class对象获取指定的属性 Field field4 = clazz.getField("publicValue"); // 3.通过get方法获取对象中该属性的值,会抛出IllegalAccessException System.out.println("获取publicValue的值: " + field4.get(classTestObject).toString()); // 注意String类型没有对应的getString()方法,但其他基本类型有 Field field5 = clazz.getField("age"); System.out.println("获取age的值: " + field5.getInt(classTestObject)); // 4. 通过set方法设置对象中该属性的值,会抛出IllegalAccessException System.out.println("============================\n" + "设置属性的值"); field4.set(classTestObject, "通过set方法设置的属性值"); System.out.println("设置后的publicValue: " + field4.get(classTestObject).toString()); field5.setInt(classTestObject, 24); System.out.println("设置后的age: " + field5.getInt(classTestObject)); // 5. get或set类的private属性 System.out.println("============================\n" + "get或set类的private属性"); Field field6 = clazz.getDeclaredField("privateValue"); // 要将其设置为可访问,否则会抛出异常 // java.lang.IllegalAccessException: Class com.lucy.Main can not access a member of class com.lucy.ClassTest with modifiers "private" field6.setAccessible(true); System.out.println("通过get获取私有属性的值: " + field6.get(classTestObject)); field6.set(classTestObject, "设置privateValue"); System.out.println("设置后的私有属性值: " + field6.get(classTestObject)); } catch (NoSuchFieldException | IllegalAccessException e) { e.printStackTrace(); } } /** * 获取类的成员方法 * * @param * @return void * @author sunrise * @date 2021/1/2 17:04 **/ public static void getMethodTest() { // 先获取类的class对象 Class clazz = ClassTest.class; // 获取类的所有公有方法(包括其父类或接口中的public方法) Method[] methods1 = clazz.getMethods(); System.out.println("============================\n" + "获取类的所有公有方法"); for (Method method : methods1) { System.out.println(method.toString()); } // 获取类的所有方法(不包括父类或接口中的方法) Method[] methods2 = clazz.getDeclaredMethods(); System.out.println("============================\n" + "获取类的所有方法"); for (Method method : methods2) { System.out.println(method.toString()); } // 通过方法名和方法参数获取指定的方法 try { System.out.println("============================\n" + "通过方法名和方法参数获取指定的方法"); Method method1 = clazz.getMethod("sayHello"); System.out.println("获取不带参数的公有方法, " + method1.toString()); Method method2 = clazz.getMethod("sayHello", String.class); System.out.println("获取带参数的公有方法, " + method2.toString()); Method method3 = clazz.getDeclaredMethod("sayHello", int.class); System.out.println("获取带参数的default方法, " + method3.toString()); Method method4 = clazz.getDeclaredMethod("sayHello", int.class, int.class); System.out.println("获取带参数的private方法, " + method4.toString()); } catch (NoSuchMethodException e) { e.printStackTrace(); } // 通过invoke调用方法 System.out.println("============================\n" + "通过invoke调用方法"); try { // 1. 进行类的实例化 ClassTest classTestObject = new ClassTest("default"); // 2. 通过类的class对象获取方法 Method method5 = clazz.getMethod("sayHello"); // 3. 通过method.invoke()调用方法 method5.invoke(classTestObject); // 调用default方法 Method method6 = clazz.getDeclaredMethod("sayHello", int.class); method6.invoke(classTestObject, 18); // 调用private方法,需要设置权限 Method method7 = clazz.getDeclaredMethod("sayHello", int.class, int.class); method7.setAccessible(true); method7.invoke(classTestObject, 21, 177); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } public static void getConstructorTest() { // 先获取的类的class对象 Class clazz = ClassTest.class; // 获取类的所有公有构造函数(不包括父类或接口的) Constructor[] constructors1 = clazz.getConstructors(); System.out.println("============================\n" + "获取类的所有公有构造函数"); for (Constructor constructor : constructors1) { System.out.println(constructor.toString()); } // 获取类的所有构造函数 Constructor[] constructors2 = clazz.getDeclaredConstructors(); System.out.println("============================\n" + "获取类的所有构造函数"); for (Constructor constructor : constructors2) { System.out.println(constructor.toString()); } // 获取指定的构造函数(通过参数) System.out.println("============================\n" + "获取指定的构造函数"); try { // 获取无参构造函数(默认构造函数) Constructor constructor1 = clazz.getConstructor(); System.out.println(constructor1.toString()); // 获取有参的公有构造函数 Constructor constructor2 = clazz.getConstructor(String.class, String.class, String.class); System.out.println(constructor2.toString()); // 获取有参的私有构造函数 Constructor constructor3 = clazz.getDeclaredConstructor(String.class, String.class); System.out.println(constructor3.toString()); } catch (NoSuchMethodException e) { e.printStackTrace(); } // 调用构造函数的newInstance方法创建类的对象 System.out.println("============================\n" + "调用构造函数的newInstance方法创建类的对象"); try { Constructor constructor4 = clazz.getConstructor(); // 通过Constructor.newInstance()进行类的实例化 ClassTest object1 = (ClassTest) constructor4.newInstance(); object1.sayHello("grace"); // 获取private的有参构造函数,并通过constructor.newInstance(params)进行类的实例化 Constructor constructor5 = clazz.getDeclaredConstructor(String.class, String.class); // private类型的constructor需要设置权限 constructor5.setAccessible(true); ClassTest object2 = (ClassTest) constructor5.newInstance("protected", "default"); object1.sayHello("lily"); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } }