Java 反射

简介: Java 反射是一种强大的特性,它允许在运行时动态地获取和操作类、对象、字段和方法的信息,可以说是强化版的自省(有点类似于 Python 的自省)。说简单点,就是可以在调用某个类的时候,能够获取和修改这个类一些东西。这也是 Java 被认为是半静态半动态语言的重要原因。

一、基本介绍

Java 反射是一种强大的特性,它允许在运行时动态地获取和操作类、对象、字段和方法的信息,可以说是强化版的自省(有点类似于 Python 的自省)。说简单点,就是可以在调用某个类的时候,能够获取和修改这个类一些东西。这也是 Java 被认为是半静态半动态语言的重要原因。

优点

  • 动态性:反射允许在运行时动态地获取和操作类的信息,而不需要在编译时知道类的具体细节。这使得编写通用的、可扩展的代码变得更加容易。
  • 灵活性:反射提供了一种灵活的方式来处理类、对象、字段和方法。它可以用于实现一些复杂的功能,如依赖注入、ORM(对象关系映射)等。
  • 框架和工具支持:许多框架和工具(如 Spring、Hibernate 等)使用反射来实现它们的功能。反射使得这些框架和工具能够在运行时自动地处理和操作类的信息。

缺点

  • 性能开销:反射通常比直接调用代码更慢。由于反射涉及到动态解析和调用,它需要更多的时间和资源。因此,在性能敏感的应用程序中,过度使用反射可能会导致性能下降。
  • 安全性问题:反射可以绕过访问控制,访问和修改私有成员。这可能会导致安全漏洞,因此在使用反射时需要谨慎处理,并确保只有授权的代码可以访问敏感信息。
  • 可读性和维护性:由于反射允许在运行时动态地操作类和对象,它可能导致代码更加复杂和难以理解。使用反射的代码可能会缺乏清晰的结构和可读性,从而增加了维护的难度。

反射是一项强大的特性,但在使用时需要权衡其优点和缺点,并根据具体情况进行选择。在某些情况下,反射是必需的,但在其他情况下,应该谨慎使用以避免潜在的性能和安全问题。简单说,就是用的好,能大大提高程序质量,用的不好,会浪费大量性能且产生安全隐患。

二、反射相关类

反射机制里面相关类有 Class、Field、Methods、Paramter 等,这里给出几个做讲解。

2.1 Class 对象

Class 类位于 java.lang.Class,不需要我们手动进行导入。得到一个类的 Class 对象的方法有三种,这三种方法得到的 Class 对象是同一个东西。

2.1.1 类的 getClass 方法

这种方法适用于已经有对象实例的情况,可以通过对象实例来获取其所属类的 Class 对象。

String str = "Java";
Class cls = str.getClass();

2.1.2 类的 class 字段

这种方法适用于已知类名的情况,可以直接在代码中获取该类的 Class 对象。

String str = "Java";
Class cls = String.class;

2.1.3 Class 的 forName 方法

这种方法最常用,适用于在运行时动态加载类的情况,可以通过类的全限定名来获取 Class 对象,这样可以在运行时根据需要加载不同的类,但是有可能会抛出 ClassNotFoundException 的异常。

Class cls = Class.forName("java.lang.String");

下面的代码分别展示了三种方法,且得到的 Class 对象是同一个东西:

String str = "Java";
Class cls2 = str.getClass(); // 实例的 getClass 方法
Class cls1 = String.class; // 类的 class 属性
Class cls3 = Class.forName("java.lang.String"); // Class 的 forName 方法
System.out.println(cls1 == cls2); // Output: true
System.out.println(cls2 == cls3); // Output: true

2.2 Field 类

Field 位于 java.lang.reflect.Field,是需要我们手动导入的,它可以用来获取字段。

下面是该类的基本方法:

方法 描述
get(Object obj) 返回 obj 对象该字段的值
set(Object obj, Object value) 修改 obj 对象该字段的值为 value
setAccessible(boolean flag) 将该字段的访问修改为 flag(true 可访问,false 不可访问)
getName() 返回该字段的名称
getType() 返回该字段的类型
getModifiers() 返回该字段的修饰符类(不是直接返回修饰符)

2.3 Method 类

Method 位于 java.lang.reflect.Method,也是需要我们手动导入的,它可以用来获取方法。

下面是该类的基本方法:

方法 描述
getName() 返回该方法的方法名
setAccessible(boolean flag) 将该方法的访问修改为 flag(true 可访问,false 不可访问)
getReturnType() 返回该方法的返回类型
getModifiers() 返回该方法的修饰符类(不是直接返回修饰符)
getParameterTypes() 以数组形式返回该方法的参数类型的 Class 对象

2.4 Modifier 类

Modifier 位于 java.lang.reflect.Modifier,同上,它可以用来获取修饰符。

下面是该类的基本方法:

方法 描述
toString(int mod) 通过 mod 值来返回对应的修饰符
isPublic(int modifiers) 判断给定的修饰符是否是 public
isStatic(int modifiers) 判断给定的修饰符是否是 static
isFinal(int modifiers) 判断给定的修饰符是否是 final
isAbstract(int modifiers) 判断给定的修饰符是否是 abstract
isInterface(int modifiers) 判断给定的修饰符是否是 interface

三、基本使用方法

3.1 获取

下面是 Class 对象部分用于获取的方法:

方法 描述
getName() 返回类的全限定名
getSimpleName() 返回类的简单名称
getFields() 返回类的 public 类型的字段
getDeclaredFields() 返回类的所有字段,包括 private 声明的和继承类的
getMethod(String name, Class[] parameterTypes) 返回类特定的方法
getMethods() 返回类的 public 类型的方法
getDeclaredMethods() 返回类的所有方法,包括 private 声明的和继承类的
getPackage() 返回类所在的包
getSuperclass() 返回类的父类
getInterfaces() 返回类实现的接口
getDeclaredFields() 返回类声明的所有字段
getConstructors() 返回类的 public 类型的构造函数
getDeclaredConstructors() 返回类声明的所有构造函数
getDeclaredAnnotations() 返回类声明的所有注解
getInterfaces() 返回类的接口

示例:

import java.lang.reflect.*; // 反射相关的类在这个包中
interface Interface {} // 接口
class Father {} // 父类
class Son extends Father implements Interface { // 子类
    public String var_public = "str";
    private String var_private;
    Son() {};
    public void method_public(Integer param) {};
    private void method_private(Double param) {};
}
public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, NoSuchMethodException {
        Son son = new Son();
        Class cls = son.getClass();
        // 获取类名
        System.out.println(cls.getName()); // Output: Son
        // 获取接口(返回一个数组)
        for (Class aClass: cls.getInterfaces()) System.out.println(aClass.getName()); // Output: Interface
        // 获取父类
        System.out.println(cls.getSuperclass().getName()); // Output: Father
        // 获取修饰符(需要用到 java.lang.reflect.Modifier)
        // 类 Son 没有修饰符,输出将为空,故此处用类 Test 来代替
        System.out.println(Modifier.toString(Test.class.getModifiers())); // Output: public
        // 获取属性(需要用到 java.lang.reflect.Field)
        System.out.println(cls.getField("var_public").get(son)); // Output: str
        // 获取方法(返回一个数组)(此处只获取声明的方法,不然太多了)
        for (Method method: cls.getDeclaredMethods()) System.out.println(method.getName()); // Output: method_public \n method_private
        // 获取方法的返回类型
        System.out.println(cls.getMethod("method_public", Integer.class).getReturnType()); // Output: void
        // 获取方法的参数类型(返回一个数组)
        for (Class aClass: cls.getMethod("method_public", Integer.class).getParameterTypes()) System.out.println(aClass.getSimpleName()); // Output: Integer
    }
}

3.2 修改

下面反射机制中用于修改的示例:

import java.lang.reflect.*;
interface Interface {}
class Father {}
class Son extends Father implements Interface {
    public String var_public = "str";
    private String var_private;
    Son() {};
    public void method_public(Integer param) {};
    private void method_private(Double param) {};
}
public class Test {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Son son = new Son();
        Class cls = son.getClass();
        Field field = cls.getDeclaredField("var_public");
        // 让该属性能够被访问(当属性为 private 的时候,需要用此修改其访问修饰符)
        field.setAccessible(true); // 当然,也可以根据需要修改为 false
        // 修改属性 var_public 的值之前
        System.out.println(field.get(son)); // Output: str
        // 修改值
        field.set(son, "new");
        // 修改属性 var_public 的值之后
        System.out.println(field.get(son)); // Output: new
    }
}
目录
相关文章
|
29天前
|
监控 Java
Java基础——反射
本文介绍了Java反射机制的基本概念和使用方法,包括`Class`类的使用、动态加载类、获取方法和成员变量信息、方法反射操作、以及通过反射了解集合泛型的本质。同时,文章还探讨了动态代理的概念及其应用,通过实例展示了如何利用动态代理实现面向切面编程(AOP),例如为方法执行添加性能监控。
|
1月前
|
Java
Java的反射
Java的反射。
29 2
|
2月前
|
存储 Java
[Java]反射
本文详细介绍了Java反射机制的基本概念、使用方法及其注意事项。首先解释了反射的定义和类加载过程,接着通过具体示例展示了如何使用反射获取和操作类的构造方法、方法和变量。文章还讨论了反射在类加载、内部类、父类成员访问等方面的特殊行为,并提供了通过反射跳过泛型检查的示例。最后,简要介绍了字面量和符号引用的概念。全文旨在帮助读者深入理解反射机制及其应用场景。
37 0
[Java]反射
|
3月前
|
安全 Java 索引
Java——反射&枚举
本文介绍了Java反射机制及其应用,包括获取Class对象、构造方法、成员变量和成员方法。反射允许在运行时动态操作类和对象,例如创建对象、调用方法和访问字段。文章详细解释了不同方法的使用方式及其注意事项,并展示了如何通过反射获取类的各种信息。此外,还介绍了枚举类型的特点和使用方法,包括枚举的构造方法及其在反射中的特殊处理。
76 9
Java——反射&枚举
|
2月前
|
安全 Java 测试技术
🌟Java零基础-反射:从入门到精通
【10月更文挑战第4天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
31 2
|
3月前
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
|
2月前
|
IDE Java 编译器
java的反射与注解
java的反射与注解
22 0
|
3月前
|
Java 程序员 编译器
Java的反射技术reflect
Java的反射技术允许程序在运行时动态加载和操作类,基于字节码文件构建中间语言代码,进而生成机器码在JVM上执行,实现了“一次编译,到处运行”。此技术虽需更多运行时间,但广泛应用于Spring框架的持续集成、动态配置及三大特性(IOC、DI、AOP)中,支持企业级应用的迭代升级和灵活配置管理,适用于集群部署与数据同步场景。
|
3月前
|
存储 安全 Java
扫盲java基础-反射(一)
扫盲java基础-反射(一)
|
3月前
|
Java
扫盲java基础-反射(二)
扫盲java基础-反射(二)