Java 反射是指在程序运行时,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。这种动态获取信息以及动态调用对象的方法的功能称为 Java 的反射机制。Java 反射是一种强大的工具,可以在运行时动态地操作类和对象。但是,反射也有一些性能开销,使用时要谨慎。尽量避免在性能敏感的代码中使用反射。本文主要介绍Java 反射(Reflection)。

1、Java 反射(Reflection)使用场景

反射在以下情况下很有用:

1)需要访问Jar包数据中的注解时。

2)检查和实例化jar包中的类型。

3)在运行时构建新类型。

4)编译时根本无法预知该对象的类型,程序只能依靠运行时来发现对象和类的具体信息

5)执行后期绑定,访问在运行时创建的类型上的方法。可以动态调用执行方法。

6)可以动态生成类框架,如Gson。

7)Tomcat服务器是典型的反射机制应用

2、Java 反射(Reflection)的使用

1)获取Class对象

通过Java代码获取Class对象有四种方法,具体如下,

import java.util.*;

public class Main {
  public static void main(String[] args) throws Exception  {
    Class<?> class1 = null;
    Class<?> class2 = null;
    Class<?> class3 = null;
    Class<?> class4 = null;
    //调用Class的静态方法:forName(全类名)    
    class1 = Class.forName("java.util.Date");
    //通过运行时类的对象的getClass方法
    class2 = new java.util.Date().getClass();
    //调用运行时类的属性
    class3 = java.util.Date.class;
    //ClassLoader中的loadClass(全类名)方式获取
    ClassLoader classLoader = Main.class.getClassLoader();
    class4 = classLoader.loadClass("java.util.Date");
        System.out.println(class4);

    System.out.println("类名称   " + class1.getName());
    System.out.println("类名称   " + class2.getName());
    System.out.println("类名称   " + class3.getName());
    System.out.println("类名称   " + class4.getName());

    System.exit(0); //success
  }
}

2)9个预定义Class对象

byte,short,int,long,char,float,double,booleanvoid关键字,都有class属性。例如,

int.class;
boolean.class;

int的包装类是IntegerIntegerint 不是同一种数据类型,8个基本数据类型的包装类中都有一个常量TYPETYPE表示的是该包装类对应的基本数据类型的Class对象,

Integer.TYPE == int.class;//true
Integer.TYPE != Integer.class;//true

3)获取类中的构造器

获取所有公有构造器:Class对象的getDeclaredConstructors();

获取所有构造器:Class对象的getDeclaredConstructors();

获取单个公有无参构造器:Class对象的getConstructor(null);

获取单个指定公有构造器:Class对象的getConstructor(String.class);

获取单个指定构造器:Class对象的getDeclaredConstructor(String.class);

4)获取成员变量的方法

方法

描述

Field[] getFields()

获取当前Class所表示类的所有public字段。

Field[] getDeclaredFields()

获取当前Class所表示类的所有字段,

包括:private、protected、默认、public。

public Field getField(String fieldName)

获取当前Class所表示类指定的public字段。

public Field getDeclaredField(String fieldName)

获取当前Class所表示类的指定字段

(可以为private)

public void set(Object obj,Object value) 

参数 obj:要设置的字段所在的对象,

value:要为字段设置的值

5)获取类中的成员方法

方法

描述

public Method[] getMethods()

获取当前Class所表示类和继承的所有public方法

(包含了父类的方法也包含Object类)。

public Method[] getDeclaredMethods()

获取当前Class所表示类的所有成员方法,

包括私有的(不包括继承的,和访问权限无关)。

public Method getMethod

(String name,

Class... parameterTypes)

获取当前Class所表示类的指定的public方法

(包括继承的)。

public Method getDeclaredMethod

(String methodName,

Class... parameterTypes)

获取当前Class所表示类的指定的成员方法

(不包括继承的)。

参数  methodName:方法名,

Class ... parameterTypes:

形参的Class类型对象

3、Java 反射使用实例

1)获取类名、修饰符和包信息

import java.lang.reflect.Modifier;

public class Main {
    public static void main(String[] args) {
        Class<?> clazz = Sample.class;

        // 获取类名和修饰符
        System.out.println("getName: " + clazz.getName() + "\tgetSimpleName: " + clazz.getSimpleName());
        int mod = clazz.getModifiers();
        System.out.println("Modifier.isPublic: " + Modifier.isPublic(mod) + "\tModifier.isProtected: " + Modifier.isProtected(mod));

        // 获取包信息
        System.out.println("getPackage: " + clazz.getPackage());
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

2)获取父类和接口信息

public class Main {
    public static void main(String[] args) {
        Class<?> clazz = Sample.class;

        // 获取父类和实现的接口
        System.out.println("getSuperclass: " + clazz.getSuperclass());
        System.out.println("getInterfaces: " + clazz.getInterfaces().length);
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

3)获取构造方法和所有方法

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        Class<?> clazz = Sample.class;

        // 获取构造方法
        System.out.println("getConstructors: " + clazz.getConstructors().length);

        // 获取并打印所有方法
        Method[] methods = clazz.getMethods();
        System.out.println("getMethods: " + methods.length);
        for (Method method : methods) {
            System.out.println("Method: " + method.getName());
        }
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

4)调用特定方法

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) throws Exception {
        Sample s = new Sample();
        s.setProp1("cjavapy.com");
        
        Class<?> clazz = Sample.class;

        // 调用特定方法
        Method getProp1Method = clazz.getMethod("getProp1");
        System.out.println("getProp1: " + getProp1Method.invoke(s));

        // 调用带参数的 setter 方法
        Method setProp3Method = clazz.getMethod("setProp3", Double.class);
        setProp3Method.invoke(s, 2.0);
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

5)获取和修改字段的值

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) throws Exception {
        Sample s = new Sample();
        s.setProp1("cjavapy.com");

        Class<?> clazz = Sample.class;

        // 获取字段并设置值
        Field[] fields = clazz.getDeclaredFields();
        System.out.println("getDeclaredFields: " + fields.length);
        for (Field field : fields) {
            field.setAccessible(true);
            field.set(s, null);  // 设置字段值为 null
            System.out.println("Field: " + field.getName() + " = " + field.get(s));
        }
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

6)获取类的注解

import java.lang.annotation.Annotation;

public class Main {
    public static void main(String[] args) {
        Class<?> clazz = Sample.class;

        // 获取类注解
        Annotation[] annotations = clazz.getAnnotations();
        System.out.println("getAnnotations: " + annotations.length);
    }
}

class Sample {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }
}

7)使用反射调用 ArrayList对象的add方法

import java.lang.reflect.Method;
import java.util.ArrayList;

public class Main {
    public static void main(String[] args) throws Exception{
        ArrayList list = new ArrayList<>();
        list.add("Java");
        list.add("CJavaPy");
  
        //获取ArrayList的Class对象,调用add()方法,添加数据
        Class listClass = list.getClass(); //得到 list对象的字节码对象
        //获取add()方法
        Method m = listClass.getMethod("add", Object.class);
        //调用add()方法
        m.invoke(list, "https://www.cjavapy.com");
        //可以通过反射越过泛型检查的,添加整型的值
        m.invoke(list,11);
        //遍历集合
        for(Object obj : list){
            System.out.println(obj);
        }
    }
}

8)使用反射为对象赋值

import java.lang.reflect.Field;

public class Main {
    private String prop1;
    private Integer prop2;
    private Double prop3;

    public String getProp1() { return prop1; }
    public void setProp1(String prop1) { this.prop1 = prop1; }
    public Integer getProp2() { return prop2; }
    public void setProp2(Integer prop2) { this.prop2 = prop2; }
    public Double getProp3() { return prop3; }
    public void setProp3(Double prop3) { this.prop3 = prop3; }

    public static Object setClassValue(Object source, Object target) {
        try {
            Field[] sourceFields = source.getClass().getDeclaredFields();
            Field[] targetFields = target.getClass().getDeclaredFields();
            for (Field sourceField : sourceFields) {
                sourceField.setAccessible(true);
                for (Field targetField : targetFields) {
                    if (sourceField.getName().equals(targetField.getName())) {
                        targetField.setAccessible(true);
                        targetField.set(target, sourceField.get(source));
                        break;
                    }
                }
            }
            return target;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static void main(String[] args) {
        try {
            Main source = new Main();
            source.setProp1("Java");
            source.setProp2(11);
            source.setProp3(22.00);
            
            Main target = new Main();
            setClassValue(source, target);
            
            System.out.println(target.getProp1() + " " + target.getProp2() + " " + target.getProp3());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

推荐文档