Java 反射

反射

反射是 Java 语言提供的一种机制,允许程序在运行时获取自身信息。

获取 Class 对象

  1. 通过 Class.forName() 获取 Class 对象,使用场景:编译时
  2. 通过 类名.class 获取 Class 对象,使用场景:加载时
  3. 通过 对象.getClass() 获取 Class 对象,使用场景:运行时
java
复制代码
// 1 Class<?> studentClass1 = Class.forName("com.code_dog.demo01.Student"); System.out.println(studentClass1); // 2 Class<Student> studentClass2 = Student.class; System.out.println(studentClass2); // 3 Student student = new Student(); Class<? extends Student> studentClass3 = student.getClass(); System.out.println(studentClass3);

获取类中的信息

分类

信息
构造方法Constructor
成员变量Field
成员方法Method
参数Parameter
注解Annotation

构造方法 Constructor

方法名描述
getConstructors()获取所有构造方法,只能获取 public 修饰的构造方法
getConstructor(Class<?>... parameterTypes)获取指定参数的构造方法
getDeclaredConstructors()获取所有声明的构造方法,包括 private 修饰的构造方法
getDeclaredConstructor(Class<?>... parameterTypes)获取指定参数的声明的构造方法
getEnclosingConstructor()获取构造方法所在的外部类
java
复制代码
Class<?> studentClass = Class.forName("com.code_dog.demo02.Student"); System.out.println(studentClass); // class com.code_dog.demo02.Student // 获取全部 public 构造方法 Constructor<?>[] constructors = studentClass.getConstructors(); System.out.println(Arrays.toString(constructors)); // [public com.code_dog.demo02.Student(java.lang.String,int), public com.code_dog.demo02.Student()] // 获取全部构造方法,包括私有的 Constructor<?>[] declaredConstructors = studentClass.getDeclaredConstructors(); System.out.println(Arrays.toString(declaredConstructors)); // [private com.code_dog.demo02.Student(java.lang.String), public com.code_dog.demo02.Student(java.lang.String,int), public com.code_dog.demo02.Student()] // 获取指定的构造方法,参数是 String 和 int 的 Constructor<?> constructor = studentClass.getConstructor(String.class, int.class); System.out.println(constructor); // public com.code_dog.demo02.Student(java.lang.String,int) // 获取指定的私有构造方法,参数是 String 的 Constructor<?> declaredConstructor = studentClass.getDeclaredConstructor(String.class); System.out.println(declaredConstructor); // private com.code_dog.demo02.Student(java.lang.String) // 获取构造方法的全部信息 // 获取权限修饰符 int modifiers = constructor.getModifiers(); System.out.println(modifiers); // 1 代表 public // 获取参数 Parameter[] parameters = constructor.getParameters(); System.out.println(Arrays.toString(parameters)); // [java.lang.String arg0, int arg1] for (Parameter parameter : parameters) { // 参数名 System.out.println(parameter.getName()); // 参数类型 System.out.println(parameter.getType()); // 参数修饰符 System.out.println(parameter.getModifiers()); // 参数注解 System.out.println(Arrays.toString(parameter.getAnnotations())); } // 执行构造方法 Student student1 = (Student) constructor.newInstance("张三", 20); System.out.println(student1); // Student{name='张三', age=20} // 执行私有构造方法 // 私有构造方法原则上不允许访问,所以需要通过 setAccessible 方法让其可访问 declaredConstructor.setAccessible(true); Student student2 = (Student) declaredConstructor.newInstance("李四"); System.out.println(student2); // Student{name='李四', age=0}

成员变量 Field

方法名描述
getFields()获取所有成员变量,只能获取 public 修饰的成员变量
getField(String name)获取指定名称的成员变量
getDeclaredFields()获取所有声明的成员变量,包括 private 修饰的成员变量
getDeclaredField(String name)获取指定名称的声明的成员变量
java
复制代码
Class<?> studentClass = Class.forName("com.code_dog.demo03.Student"); System.out.println(studentClass); // class com.code_dog.demo03.Student // 获取全部 public 成员变量 Field[] fields = studentClass.getFields(); System.out.println(Arrays.toString(fields)); // [public double com.code_dog.demo03.Student.height] // 获取全部成员变量,包括私有的 Field[] declaredFields = studentClass.getDeclaredFields(); System.out.println(Arrays.toString(declaredFields)); // [private java.lang.String com.code_dog.demo03.Student.name, private int com.code_dog.demo03.Student.age, public double com.code_dog.demo03.Student.height] // 获取指定成员变量 Field height = studentClass.getField("height"); System.out.println(height); // public double com.code_dog.demo03.Student.height // 获取私有的成员变量 Field name = studentClass.getDeclaredField("name"); System.out.println(name); // private java.lang.String com.code_dog.demo03.Student.name // 获取成员变量中的信息 // 访问修饰符 int modifiers = height.getModifiers(); System.out.println(modifiers); // 1 // 变量名 String name1 = height.getName(); System.out.println(name1); // height // 数据类型 Class<?> type = height.getType(); System.out.println(type); // double // 取值 Student student = new Student("张三", 20, 180.2); // public Object heightValue = height.get(student); System.out.println(heightValue); // 180.2 // private,同理,需要先设置可访问 name.setAccessible(true); Object nameValue = name.get(student); System.out.println(nameValue); // 张三 // 赋值 height.set(student, 170); name.set(student, "李四"); System.out.println(student); // Student{name='李四', age=20, height=170.0}

成员方法 Method

方法名描述
getMethods()获取所有成员方法,只能获取 public 修饰的成员方法
getMethod(String name, Class<?>... parameterTypes)获取指定名称和参数的成员方法
getDeclaredMethods()获取所有声明的成员方法,包括 private 修饰的成员方法
getDeclaredMethod(String name, Class<?>... parameterTypes)获取指定名称和参数的声明的成员方法
java
复制代码
Class<?> studentClass = Class.forName("com.code_dog.demo04.Student"); System.out.println(studentClass); // class com.code_dog.demo04.Student // 获取全部方法,父类方法也可以获取到 Method[] methods = studentClass.getMethods(); System.out.println(Arrays.toString(methods)); // [public java.lang.String com.code_dog.demo04.Student.getName(), // public java.lang.String com.code_dog.demo04.Student.toString(), // public void com.code_dog.demo04.Student.setName(java.lang.String), // public int com.code_dog.demo04.Student.getAge(), // public void com.code_dog.demo04.Student.setAge(int), // public boolean java.lang.Object.equals(java.lang.Object), // public native int java.lang.Object.hashCode(), // public final native java.lang.Class java.lang.Object.getClass(), // public final native void java.lang.Object.notify(), // public final native void java.lang.Object.notifyAll(), // public final void java.lang.Object.wait(long) throws java.lang.InterruptedException, // public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, // public final void java.lang.Object.wait() throws java.lang.InterruptedException] // 无法获取父类,但可以获取私有方法 Method[] declaredMethods = studentClass.getDeclaredMethods(); System.out.println(Arrays.toString(declaredMethods)); // [public java.lang.String com.code_dog.demo04.Student.getName(), // public java.lang.String com.code_dog.demo04.Student.toString(), // private void com.code_dog.demo04.Student.method(java.lang.String), // public void com.code_dog.demo04.Student.setName(java.lang.String), // public void com.code_dog.demo04.Student.setAge(int), // public int com.code_dog.demo04.Student.getAge()] // 获取指定方法 Method getName = studentClass.getMethod("getName"); System.out.println(getName); // public java.lang.String com.code_dog.demo04.Student.getName() Method setName = studentClass.getMethod("setName", String.class); System.out.println(setName); // public void com.code_dog.demo04.Student.setName(java.lang.String) // 获取私有指定方法 Method method = studentClass.getDeclaredMethod("method", String.class); System.out.println(method); // private void com.code_dog.demo04.Student.method(java.lang.String) // 获取方法信息 // 访问修饰符 int modifiers = getName.getModifiers(); System.out.println(modifiers); // 1 int modifiers1 = method.getModifiers(); System.out.println(modifiers1); // 2 // 方法名 String name = setName.getName(); System.out.println(name); // setName // 方法参数 Parameter[] parameters = setName.getParameters(); System.out.println(Arrays.toString(parameters)); // [java.lang.String arg0] // 方法注解 Method toString = studentClass.getMethod("toString"); Annotation[] annotations = toString.getAnnotations(); // Override 是编译时注解,所以程序运行时注解不存在,就获取不到 System.out.println(Arrays.toString(annotations)); // [] // 方法异常 Class<?>[] exceptionTypes = setName.getExceptionTypes(); System.out.println(Arrays.toString(exceptionTypes)); // [class java.io.IOException] // 运行方法 Student student = new Student("张三", 20 ,180.0); setName.invoke(student, "李四"); System.out.println(student); // Student{name='李四', age=20, height=180.0} // 有返回值 Object invoke = getName.invoke(student); System.out.println(invoke); // 李四 // 私有方法 method.setAccessible(true); method.invoke(student, "Tom"); // Hello Tom

综合练习

保存任意对象至文件中,格式:属性名=属性值

java
复制代码
public static void main(String[] args) { Student student = new Student("张三", 20, '男', 180.0, 150.0); Teacher teacher = new Teacher("李四", 20); try { save(student); save(teacher); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } public static void save(Object object) throws IllegalAccessException, IOException { Class<?> clazz = object.getClass(); Field[] declaredFields = clazz.getDeclaredFields(); BufferedWriter bw = new BufferedWriter(new FileWriter(System.getProperty("user.dir") + File.separator + "text.txt")); for (Field field : declaredFields) { field.setAccessible(true); String name = field.getName(); Object value = field.get(object); System.out.println(name + "=" + value); bw.write(name + "=" + value); bw.newLine(); } bw.close(); }

根据配置文件动态创建对象

java
复制代码
File file = new File(System.getProperty("user.dir") + File.separator + "prop.properties"); FileInputStream fileInputStream = new FileInputStream(file); Properties prop = new Properties(); prop.load(fileInputStream); System.out.println(prop); // {methodName=study, className=com.code_dog.demo06.Student} String className = prop.get("className").toString(); String methodName = prop.get("methodName").toString(); System.out.println(className); // com.code_dog.demo06.Student System.out.println(methodName); // study Class<?> clazz = Class.forName(className); Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(); declaredConstructor.setAccessible(true); Object object = declaredConstructor.newInstance(); Method method = clazz.getDeclaredMethod(methodName); method.setAccessible(true); method.invoke(object); // Student is studying

动态代理

动态代理: 在程序运行时,动态地创建一个代理对象,代理对象会替代某个对象,并调用被代理对象的方法

举个简单的例子,比如一个对象,在执行每个方法前都需要打印日志,但是如果在每个方法中都添加打印日志的代码,那么代码就会重复很多遍,或者说,这个代码我已经写好了,我不想修改原始代码,但是又想给原始代码添加功能,这时就可以使用动态代理。

动态代理就是在运行时,动态地创建一个代理对象,这个代理对象会可以在真实对象执行前后添加额外的功能,比如打印日志,性能监控,安全控制等等。

  1. 创建代理对象
  2. 执行代理对象的方法
  3. 使用代理对象调用真实对象的方法
java
复制代码
public interface ProxyInter { void study(String subject); }
java
复制代码
public static void main(String[] args) { // 创建代理对象 Student student = new Student("张三", 20); ProxyInter proxy = createProxy(student); proxy.study("数学"); } public static ProxyInter createProxy(Object object) { Object proxyObject = Proxy.newProxyInstance( object.getClass().getClassLoader(), // 类加载器 new Class[]{ProxyInter.class}, // 接口,代理对象会拥有接口中的方法,可以传递多个接口 new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 模拟日志 System.out.println(LocalDateTime.now() + " " + proxy.getClass().getName() + " " + method.getName() + " " + Arrays.toString(args)); return method.invoke(object, args); } } ); return (ProxyInter) proxyObject; }
0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP