Java反射

第 1 章 Java 反射

1.1 反射的概述

1.1.1 什么反射

JAVA反射(Reflection)机制是在运行状态中,对于任意一个类, 都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java的反射机制。

反射是程序的自我分析能力,通过反射可以确定类有哪些方法、有哪些构造方法以及有哪些成员变量。通过反射机制能够动态读取一个类的信息;能够在运行时动态加载类,而不是在编译期。反射可以应用于框架开发,它能够从配置文件中读取配置信息动态加载类、创建对象,以及调用方法和成员变量。

下面我们解剖一下对象的创建过程

如果一个class文件已经加载到内存(第3步),是不是就可以从class对象中获取类的方法和属性呢?这就是Java的反射。

1.1.2 反射的主要用途

反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 Bean),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射,运行时动态加载需要加载的对象。也就是我们将类名配置在配置文件中,Java反射通过类名来创建类的对象,并调用对象的方法和使用对象的属性。

反射拥有以下四大功能:

(1)在运行时(动态编泽)获知任意一个对象所属的类。

(2)在运行时构造任意个类的对象。

(3)在运行时获知任意一个类所具有的成员变量和方法。

(4)在运行时调用任意一个对象的方法和属性。

1.1.3反射机制的优点

(1)增加灵活性和扩展性:使用反射机制可以在程序运行时动态加载、修改、创建、调用类和方法等,从而增加了程序的灵活性和可扩展性。

(2)提高代码的通用性:通过反射机制可以动态的获取类信息,从而可以编写通用的代码,使得不同的类能够以相同的方式来处理。

(3)规范代码结构:反射机制可以使代码结构清晰明了,减少了代码中的冗余部分。

(4)实现框架和插件:反射机制在很多框架和插件中都有广泛的应用,比如Spring框架、 JUnit测试框架等。

(5)动态代理:反射机制的另一个重要应用是实现动态代理,可以在不修改原来代码的情况下,通过代理对象对原对象的方法进行增强。

1.2 反射的使用

1.2.1 Class 类

Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法。

1、获得类相关的方法

方法用途
asSubclass(Class clazz)把传递的类的对象转换成代表其子类的对象
Cast把对象转换成代表类或是接口的对象
getClassLoader()获得类的加载器
getClasses()返回一个数组,数组中包含该类中所有公共类和接口类的对象
getDeclaredClasses()返回一个数组, 数组中包含该类中所有类和接口类的对象
forName(String className)根据类名返回类的对象
getName()获得类的完整路径名字
newInstance()创建类的实例
getPackage()获得类的包
getSimpleName()获得类的名字
getSuperclass()获得当前类继承的父类的名字
getInterfaces()获得当前类实现的类或是接口

2、获得类中属性相关的方法

方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象

3、获得类中构造器相关的方法

方法用途
getConstrutor(Class…<?> parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获得该类中与参数类型配匹的构造方法
getDeclaredConstructors()获得该类所有构造方法

1.2.2 获取类信息

(1)创建一个学生类

/**
 * 学生类
 */

public class Student {
    private Long id;
    private String name;
    public Student() {
    }

    public Student(Long id, String name) {
        this.id = id;
        this.name = name;
    }

    public Long getId() {

        return id;

    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }

    public String concat(Long id,String name){
        return name + id;
    }
}

(2)创建测试类,通过反射来获取类的信息

public class StudentTest {

    @Test
    public void test1() throws Exception{

        /*
         * 1、加载类:已知类名获取类
         * (1)Class.forname(类的全名):通过类名加载
         * (2)类名.class:通过字节码文件加载
         * (3)类实例名.getClass():通过类实例加载
         */

        Class<?> clazz = Class.forName("org.example.Student");
        
        //Class<?> clazz = Student.class;

        /*
         * 2、创建类实例
         * (1) newlnstance():方法内部实际上调用了无参数构造方法,
         * 必须保证无参构造存在,在新版本中已标记过时
         * (2)class.getDeclaredConstructor(...构造参数类)
         * .newInstance(...参数):可带参数
         */
        Object o = clazz.getDeclaredConstructor(Long.class,String.class)
                .newInstance(1001L,"张三");
        // 调用方法toString
        System.out.println(o.toString());
    }
}

1.2.3 Method 类

Method类方法

方法名用途
getName()返回方法名
getModifiers()获取方法的修饰符列表,返回的修饰符是一个数字, 每个数字是修饰符的代号[一般配合Modifier类的toString(int x)方法使用]
getReturnType()以Class类型,返回方法类型[一般配合Class类的getSimpleName()方法使用]
getParameterTypes()返回方法的修饰符列表(一个方法的参数可能会有多个) [结果集-一般配合Class类的getSimpleName()方法使用]
invoke(Object obj, Object… args)调用方法

1.2.4 反射动态方法调用

创建测试方法,通过反射动态调用方法

@Test
public void test2() throws Exception{

    // 1、加载类
    Class<?> clazz = Class.forName("org.example.Student");

    // 2、创建类实例
    Object o = clazz.getDeclaredConstructor().newInstance();

    // 3、获取setId,setName和concat方法:已知方法名获取方法
    Method setId = clazz.getDeclaredMethod("setId", Long.class);
    Method setName = clazz.getDeclaredMethod("setName", String.class);
    Method concat = clazz.getDeclaredMethod("concat", Long.class, String.class);

    // 4、执行方法
    setId.invoke(o,1001L);

    setName.invoke(o,"张三");

    String stuinfo = (String) concat.invoke(o, 1002L, "李四");

    // 5、输出
    System.out.println(o.toString());

    System.out.println(stuinfo);
}

1.2.5 Field 类

Field类方法

方法名用途
getName()返回属性名
getModifiers()获取属性的修饰符列表,返回的修饰符是一个数字, 每个数字是修饰符的代号[一般配合Modifer类的toString(int x)方法使用]
getType()以Class类型,返回属性类型[一般配合Class类的getSimpleName()方法使用]
set(Object obj, Object value)设置属性值
get(Object obj)读取属性值

1.2.6 反射动态属性读写

创建测试方法,通过反射动态读写属性

 @Test
 public void test3() throws Exception{

        // 1、加载类
        Class<?> clazz = Student.class;

        // 2、创建类实例
        Object o = clazz.getDeclaredConstructor().newInstance();

        // 3、获取id,name属性:已知属性名获取属性
        Field id = clazz.getDeclaredField("id");
        Field name = clazz.getDeclaredField("name");

        // 4、给属性赋值
        id.setAccessible(true);// 解除属性的写保护
        id.set(o,1001L);
        name.setAccessible(true);
        name.set(o,"张三");

        // 5、读取属性值
        System.out.println(id.get(o) + "\t" + name.get(o));

    }

【总结】

Java反射是一种强大的特性, 它允许我们在运行时获取和操作类的信息。通过反射,我们可以动态地创建对象、调用方法、访问和修改字段。

在JavaBean工 具中,使用反射机制可以获取类的属性名、属性值、调用属性的setter和getter方法等信息, 方便进行对象的序列化与反序列化操作。反射机制还可以实现动态代理,实现不改变原来代码的情况下,对原来对象的方法进行增强。

### Java反射机制使用教程及常见问题 Java反射机制是一种强大的工具,允许程序在运行时动态地检查和操作类、接口、字段和方法等内部信息[^1]。以下是关于Java反射机制的详细教程以及一些常见的问题。 #### 1. 反射机制的基本概念 Java反射机制是Java语言中一种动态访问、检测和修改自身的能力,主要作用是在运行时获取类的完整结构信息并对其进行操作[^2]。通过反射,可以实现以下功能: - 动态创建对象。 - 动态调用方法。 - 动态访问字段。 - 动态处理注解。 #### 2. 核心类与API Java反射的核心类位于`java.lang.reflect`包中,主要包括以下几类: - `Class`:表示类的运行时类对象,可以通过`Class.forName(String className)`或`Object.getClass()`获取。 - `Field`:表示类的成员变量。 - `Method`:表示类的方法。 - `Constructor`:表示类的构造方法。 #### 3. 使用示例 以下是一个简单的反射机制使用示例,展示了如何通过反射创建对象并调用方法。 ```java import java.lang.reflect.Method; public class ReflectionExample { public static void main(String[] args) throws Exception { // 获取目标类的Class对象 Class<?> cls = Class.forName("com.example.MyClass"); // 创建目标类的实例 Object obj = cls.getDeclaredConstructor().newInstance(); // 获取目标类的方法 Method method = cls.getMethod("myMethod", String.class); // 调用目标类的方法 method.invoke(obj, "Hello Reflection"); } } ``` #### 4. 性能问题 反射机制虽然强大,但在性能上存在一定的开销。例如,在大量调用反射方法时,其性能可能显著低于直接调用[^4]。因此,在实际开发中应权衡使用反射的必要性。 #### 5. 常见问题 - **安全性问题**:反射可以访问私有成员,这可能导致破坏封装性[^1]。 - **性能问题**:反射调用方法的性能比普通方法调用低[^4]。 - **异常处理**:反射操作容易抛出多种异常,如`ClassNotFoundException`、`NoSuchMethodException`等,需要妥善处理。 #### 6. 实际应用场景 Java反射机制在许多实际场景中发挥了重要作用,包括但不限于框架设计、动态代理、依赖注入、测试工具和序列化/反序列化等[^3]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值