Java 反射总结

Java 反射是 Java 语言的一种特性,可以在运行时检查和调用类、方法、字段等详细信息,而不需要在编译时知道这些信息。
反射为 Java 提供了动态的能力,使程序可以在运行时动态地创建对象、调用方法、访问字段等。

基本概念

  • Class对象:反射的核心类,通过它可以获得类的详细信息。
  • Method对象:表示类中的方法,允许调用方法。
  • Field对象:表示类中的成员变量,允许访问和修改变量。
  • Constructor对象:表示类的构造函数,允许实例化对象。

获取 Class 对象的方式

获取 Class 对象的方式有:

  • 使用类名 .class
  • 使用 Class.forName("类的全限定名")
  • 使用对象 .getClass()
  • 使用 ClassLoader.loadClass() 方法

使用类名 .class

直接获取类对象的最简单方法,通常用于已知类的情况。

// 获取 String 类的 Class 对象
Class<String> clazz = String.class;

使用 Class.forName()

根据给定的类名(全限定名)在运行时加载类。它会抛出 ClassNotFoundException,因此需处理异常。

try {
    // 通过类名获取 Class 对象
    Class<?> clazz = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

使用对象 .getClass()

用于在运行时获取对象的类

// 通过对象获取 Class 对象
String str = "Hello, World!";
Class<? extends String> clazz = str.getClass();

使用 ClassLoader.loadClass() 方法

使用类加载器来加载类,通常只在特定情况下需要,如自定义类加载器。

try {
    // 获取系统类加载器
    ClassLoader classLoader = ClassLoader.getSystemClassLoader();
    // 通过类加载器加载 Class 对象
    Class<?> clazz = classLoader.loadClass("java.lang.String");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

获取类的信息

能获取到的类的信息有:

  • 获取类的名字
  • 获取类的修饰符
  • 获取类的注解
  • 获取泛型类的泛型
  • 获取类实现的接口
  • 获取类的父类

获取类的名字

  • 使用 Class.getName()方法获取类的全限定名,包括包名。
package com.demo;
public class Example {
    public static void main(String[] args) {
        Class<?> clazz = Example.class;
        String className = clazz.getName();
        System.out.println("Class name: " + className);  //Class name: com.demo.Example
    }
}
  • 使用 Class.getSimpleName()方法返回类的简单名称,不包括包名。
package com.demo;
public class Example {
    public static void main(String[] args) {
        Class<?> clazz = Example.class;
        String simpleName = clazz.getSimpleName();
        System.out.println("Simple class name: " + simpleName); // Simple class name: Example
    }
}
  • 使用 Class.getCanonicalName()方法返回类的规范名称,如果类没有规范名称(如匿名类),则返回 null。
public class Example {
    public static void main(String[] args) {
        Class<?> clazz = Example.class;
        String canonicalName = clazz.getCanonicalName();
        System.out.println("Canonical class name: " + canonicalName); // Canonical class name: com.demo.Example
    }
}

获取类的修饰符

使用 Class 类的 getModifiers()方法获取修饰符。

class SomeClass {
    // 类定义
}
public class ModifierExample {
    public static void main(String[] args) {
        Class<?> clazz = SomeClass.class;
        int modifiers = clazz.getModifiers();
        
        System.out.println("Is public: " + Modifier.isPublic(modifiers));
        System.out.println("Is abstract: " + Modifier.isAbstract(modifiers));
        System.out.println("Is final: " + Modifier.isFinal(modifiers));
        // 可以继续检查其他修饰符
    }
}
  • 输出结果:
Is public: false
Is abstract: false
Is final: false

获取类的注解

使用 Class 的 getAnnotation()方法

Class.getAnnotation(Class<T> annotationClass) 方法用于获取指定类型的注解。如果该注解不存在,则返回 null。

@Retention(RetentionPolicy.RUNTIME)  
@interface MyAnnotation {  
    String value();  
}  
  
@MyAnnotation("ExampleClass")  
class Example {  
}  
  
public class AnnotationExample1 {  
    public static void main(String[] args) {  
        Class<Example> obj = Example.class;  
          
        // 获取类上的注解  
        MyAnnotation annotation = obj.getAnnotation(MyAnnotation.class);  
          
		System.out.println("Value: " + annotation.value());  //Value: ExampleClass
    }  
}

使用 Class 的 getAnnotations()方法

Class.getAnnotations() 方法返回该元素上存在的所有注解,包含从超类继承的注解。

@Retention(RetentionPolicy.RUNTIME)  
@interface MyAnnotation {  
    String value();  
}  
  
@MyAnnotation("ExampleClass")  
class Example {  
}  
public class AnnotationExample2 {
    public static void main(String[] args) {
        Class<Example> obj = Example.class;
        
        // 获取类上所有的注解
        Annotation[] annotations = obj.getAnnotations();
        
        for (Annotation annotation : annotations) {
            if (annotation instanceof MyAnnotation) {
                MyAnnotation myAnnotation = (MyAnnotation) annotation;
                System.out.println("Value: " + myAnnotation.value());//Value: ExampleClass
            }
        }
    }
}

使用 Class 的 getDeclaredAnnotations()方法

Class.getDeclaredAnnotations() 方法返回直接存在于此元素上的所有注解,不包括继承的注解。

public class AnnotationExample3 {
    public static void main(String[] args) {
        Class<Example> obj = Example.class;
        
        // 获取类上直接声明的所有注解
        Annotation[] annotations = obj.getDeclaredAnnotations();
        
        for (Annotation annotation : annotations) {
            if (annotation instanceof MyAnnotation) {
                MyAnnotation myAnnotation = (MyAnnotation) annotation;
                System.out.println("Value: " + myAnnotation.value());
            }
        }
    }
}

使用 AnnotatedElement 的 isAnnotationPresent()方法

Class.isAnnotationPresent(Class<? extends Annotation> annotationClass) 用于检查指定类型的注解是否存在。

public class AnnotationExample4 {
    public static void main(String[] args) {
        Class<Example> obj = Example.class;
        
        // 检查注解是否存在
        if (obj.isAnnotationPresent(MyAnnotation.class)) {
            MyAnnotation annotation = obj.getAnnotation(MyAnnotation.class);
            System.out.println("Value: " + annotation.value());
        } else {
            System.out.println("MyAnnotation not present.");
        }
    }
}

获取泛型类的泛型

使用 Class 的 getGenericSuperclass()方法

如果一个类直接继承了一个带有泛型的父类,可以使用 getGenericSuperclass()获取父类的泛型类型。

class GenericClass<T> {
}

class StringGenericClass extends GenericClass<String> {
}

public class Main {
    public static void main(String[] args) {
        // 获取直接父类的泛型类型
        Type genericSuperclass = StringGenericClass.class.getGenericSuperclass();
        if (genericSuperclass instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
            Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
            for (Type type : actualTypeArguments) {
                System.out.println(type.getTypeName());  // 输出:java.lang.String
            }
        }
    }
}

使用 Class 的 getGenericInterfaces()方法

如果一个类实现了一个带有泛型的接口,可以使用 getGenericInterfaces()获取接口的泛型类型。

interface GenericInterface1<T> {  
}  
  
interface GenericInterface2<T> {}  
  
class StringGenericClass implements GenericInterface1<String>, GenericInterface2<Integer> {  
}  
  
public class Main {  
    public static void main(String[] args) {  
        // 获取实现的接口的泛型类型  
        Type[] genericInterfaces = StringGenericClass.class.getGenericInterfaces();  
        for (Type genericInterface : genericInterfaces) {  
            if (genericInterface instanceof ParameterizedType) {  
                ParameterizedType parameterizedType = (ParameterizedType) genericInterface;  
                Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();  
                for (Type type : actualTypeArguments) {  
                    System.out.println(type.getTypeName());  // 输出:java.lang.String 和 java.lang.Integer
                }  
            }  
        }  
    }  
}

获取类实现的接口

Class.getInterfaces() 方法返回表示类或接口直接实现的所有接口的数组。

public class InterfaceExample {
    public static void main(String[] args) {
        Class<?>[] interfaces = MyClass.class.getInterfaces();
        for (Class<?> iface : interfaces) {
            System.out.println(iface.getName());
        }
    }
}

interface MyInterface1 {}
interface MyInterface2 {}

class MyClass implements MyInterface1, MyInterface2 {}

获取类的父类

Class.getSuperclass() 方法可以用来获取一个类的直接父类。如果该类没有继承其他类(除了 Object 类),则返回 null

class Parent {
}

class Child extends Parent {
}

public class Main {
    public static void main(String[] args) {
        Class<?> childClass = Child.class;
        Class<?> parentClass = childClass.getSuperclass();
        System.out.println("Parent class of Child: " + parentClass.getName()); //Parent class of Child: com.demo.Parent
    }
}

操作类的字段

操作类的字段包括:

  • 获取字段
  • 访问字段的值
  • 修改字段的值

获取类的字段信息

使用 Class 的 getField() 方法

该方法用于获取类的公共成员字段(public fields),包括从父类继承的公共字段。

abstract class AbstractClass {

    public int abstractPublicField;
}

class MyClass extends AbstractClass{

    public int publicField;
    private String privateField;
}
public class Example {
    public static void main(String[] args) {
        try {
            Class<?> clazz = MyClass.class;
            Field field = clazz.getField("publicField");
            System.out.println("Field Name: " + field.getName()); // Field Name: publicField
            System.out.println("Field Type: " + field.getType()); // Field Type: int
            System.out.println("Field Modifiers: " + field.getModifiers()); // Field Modifiers: 1
            System.out.println("Field Declaring Class: " + field.getDeclaringClass()); // Field Declaring Class: class com.example.demo.MyClass

            field = clazz.getField("abstractPublicField");
            System.out.println("Field Name: " + field.getName()); // Field Name: abstractPublicField
            System.out.println("Field Type: " + field.getType()); // Field Type: int


            field = clazz.getField("privateField"); // java.lang.NoSuchFieldException: privateField

        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

使用 Class.getFields() 方法

返回一个包含所有公共成员字段的数组,包括从父类继承的公共字段。

abstract class AbstractClass {

    public int abstractPublicField;
}

class MyClass extends AbstractClass{

    public int publicField;
    private String privateField;
}
public class Example {
    public static void main(String[] args) {
        Class<?> clazz = MyClass.class;
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println("Public Field: " + field.getName());
            // 输出结果
            // Public Field: publicField
			// Public Field: abstractPublicField
        }
    }
}

使用 Class.getDeclaredField() 方法

该方法用于获取类本身声明的字段(private, protected, package-private, public),但不包括从父类继承的字段。

class MyClass {

    public int publicField;
    private String privateField;
}
public class Example {
    public static void main(String[] args) {
        try {
            Class<?> clazz = MyClass.class;
            Field field = clazz.getDeclaredField("privateField");
            System.out.println("Field Name: " + field.getName()); // Field Name: privateField
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

使用 Class.getDeclaredFields() 方法

返回一个包含类中声明的所有字段的数组,无论其访问修饰符是什么,但不包括从父类继承的字段。

class MyClass {  
  
    public int publicField;  
    private String privateField;  
}  
public class Example {  
    public static void main(String[] args) {  
        Class<?> clazz = MyClass.class;  
        Field[] fields = clazz.getDeclaredFields();  
        for (Field field : fields) {  
            System.out.println("Declared Field: " + field.getName());
            // 输出结果
            // Declared Field: publicField
			// Declared Field: privateField
        }  
    }  
}

访问字段的值

使用 Field.get() 方法

使用 Field 对象的 get(Object obj) 方法来获取指定对象上此 Field 表示的字段的值。

class Person {
    private String name = "John";
}

public class Main {
    public static void main(String[] args) throws Exception {
        Person person = new Person();

        // 获取 Person 类的 Class 对象
        Class<?> clazz = person.getClass();

        // 获取名为 "name" 的 Field 对象
        Field field = clazz.getDeclaredField("name");

        // 因为 name 是 private 的,所以需要设置为 true 以跳过访问检查
        field.setAccessible(true);

        // 获取 person 对象的 name 字段的值
        String nameValue = (String) field.get(person);

        System.out.println("Name: " + nameValue); // Name: John
    }
}

通过 Field 的 getInt()、getBoolean() 等方法

如果知道字段的具体类型,可以使用对应的 getType() 方法来获取特定类型的字段值,例如 getInt()、getBoolean() 等。

class Person {
    private String name = "John";
    private int age = 30;
}

public class Main {
    public static void main(String[] args) throws Exception {
        Person person = new Person();

        // 获取 Person 类的 Class 对象
        Class<?> clazz = person.getClass();

        // 获取名为 "name" 的 Field 对象
        Field field = clazz.getDeclaredField("age");

        // 因为 name 是 private 的,所以需要设置为 true 以跳过访问检查
        field.setAccessible(true);

        // 获取 person 对象的 name 字段的值
        int ageValue = field.getInt(person);

        System.out.println("Age: " + ageValue); // Age: 30
    }
}

使用 MethodHandle(Java 7 及以上版本)

从 Java 7 开始,可以使用 MethodHandles.Lookup 类来更高效地进行反射操作。

class Person {
    public String name = "John";
    private int age = 30;
}

public class Main {
    public static void main(String[] args) throws Throwable {
        Person person = new Person();

        // 获取 VarHandle
        VarHandle varHandle = MethodHandles.lookup().findVarHandle(Person.class, "name", String.class);

        // 获取 person 对象的 name 字段的值
        String nameValue = (String) varHandle.get(person);

        System.out.println("Name: " + nameValue);
    }
}
  • 使用 MethodHandles 只能获取类的非私有变量,类似于 getFiled() 方法,可以获取自身与父类的非私有变量。

修改字段的值

import java.lang.reflect.Field;

public class ReflectionExample {
    private String privateField = "Initial Value";

    public static void main(String[] args) {
        try {
            ReflectionExample obj = new ReflectionExample();
            Field field = ReflectionExample.class.getDeclaredField("privateField");
            field.setAccessible(true);
            field.set(obj, "Modified Value");

            System.out.println(field.get(obj)); // 输出: Modified Value
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

操作类的构造函数

操作类的构造函数包括:

  • 获取构造函数
  • 创建根据构造函数实例

获取构造函数

获取所有公共构造函数

使用 Class.getConstructors()方法获取所有公共构造函数。

public class Example {
    public Example() {}
    private Example(String s) {}

    public static void main(String[] args) {
        try {
            Class<?> cls = Example.class;
            Constructor<?>[] constructors = cls.getConstructors();

            for (Constructor<?> constructor : constructors) {
                System.out.println("Constructor: " + constructor);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

获取所有构造函数(包括非公)

使用 Class.getDeclaredConstructors() 方法获取所有级别的构造函数。

public class Example {
    private Example() {}
    protected Example(int num) {}
    Example(double value) {}
    public Example(String s) {}

    public static void main(String[] args) {
        try {
            Class<?> cls = Example.class;
            Constructor<?>[] constructors = cls.getDeclaredConstructors();

            for (Constructor<?> constructor : constructors) {
                System.out.println("Constructor: " + constructor);
                // output:
                // Constructor: public com.example.demo.Example(java.lang.String)
				// Constructor: com.example.demo.Example(double)
				// Constructor: protected com.example.demo.Example(int)
				// Constructor: private com.example.demo.Example()
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

获取特定的构造函数

使用 Class.getConstructor(Class<?>... parameterTypes) 方法获取带有特定参数类型的公共构造函数。

public class Example {
    public Example(String s) {}

    public static void main(String[] args) {
        try {
            Class<?> cls = Example.class;
            Constructor<?> constructor = cls.getConstructor(String.class);
            System.out.println("Constructor: " + constructor);
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
    }
}

获取特定的公共构造函数(包括非公)

使用 Class.getDeclaredConstructor(Class<?>... parameterTypes) 方法获取带有特定参数类型的构造函数,包括非公共构造函数。

import java.lang.reflect.Constructor;

public class Example {
    private Example(String s) {}

    public static void main(String[] args) {
        try {
            Class<?> cls = Example.class;
            Constructor<?> constructor = cls.getDeclaredConstructor(String.class);
            System.out.println("Constructor: " + constructor);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

根据构造函数创建实例

// Example.java
public class Example {
    private String name = "John";
    public Example() {}
    private Example(String s) {
        this.name = s;
    }

    public String getName() {
        return name;
    }
}
// Main.java
public class Main {
    public static void main(String[] args) {
        try {
            Class<?> cls = Example.class;
            Constructor<?> constructor = cls.getDeclaredConstructor();
            Example e1 = (Example) constructor.newInstance();
            System.out.println(e1.getName()); // John

            constructor = cls.getDeclaredConstructor(String.class);
            // 由于是私有构造函数,实例化时需要设置可访问性
            constructor.setAccessible(true);
            Example e2 = (Example) constructor.newInstance("Jane");
            System.out.println(e2.getName()); // Jane
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

操作类的方法

操作类的方法包括::

  • 获取方法
  • 调用方法

获取方法

获取所有公共方法(包括继承的方法)

使用 Class.getMethods() 方法可以获取某个类的所有公共方法,包括从父类继承的方法。

class AbstractClass {
    public void abstractMethod() {}
}


class SampleClass extends AbstractClass {
    public void sampleMethod() {}
    private void privateMethod() {}
}


public class ReflectionExample {
    public static void main(String[] args) {
        Class<?> clazz = SampleClass.class;
        Method[] methods = clazz.getMethods();

        for (Method method : methods) {
            System.out.println("Method Name: " + method.getName() + "; Declaring Class Name:" + method.getDeclaringClass().getSimpleName());
        }
    }
}
  • 输出结果:
Method Name: sampleMethod; Class Name:SampleClass
Method Name: abstractMethod; Class Name:AbstractClass
Method Name: equals; Class Name:Object
Method Name: toString; Class Name:Object
Method Name: hashCode; Class Name:Object
Method Name: getClass; Class Name:Object
Method Name: notify; Class Name:Object
Method Name: notifyAll; Class Name:Object
Method Name: wait; Class Name:Object
Method Name: wait; Class Name:Object
Method Name: wait; Class Name:Object

获取所有声明的方法(不包括继承的方法)

使用 Class.getDeclaredMethods() 方法可以获取类中声明的所有方法,包括私有方法,但不包括继承的方法。

class AbstractClass {
    public void abstractMethod() {}
}


class SampleClass extends AbstractClass {
    public void sampleMethod() {}
    private void privateMethod() {}
}


public class ReflectionExample {
    public static void main(String[] args) {
        Class<?> clazz = SampleClass.class;
        Method[] methods = clazz.getDeclaredMethods();

        for (Method method : methods) {
            System.out.println("Method Name: " + method.getName() + "; Declaring Class Name:" + method.getDeclaringClass().getSimpleName());
        }
    }
}
  • 输出结果:
Method Name: sampleMethod; Declaring Class Name:SampleClass
Method Name: privateMethod; Declaring Class Name:SampleClass

获取特定的方法(只有非私有方法)

使用 Class.getMethod(String name, Class<?>... parameterTypes) 可以获取特定的公共方法。需要提供方法名和参数类型列表。


public class ReflectionExample {
    public static void main(String[] args) {
        try {
            Class<?> clazz = SampleClass.class;
            Method method = clazz.getMethod("sampleMethod");
            System.out.println("Method Name: " + method.getName()); // Method Name: sampleMethod
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

class SampleClass {
    public void sampleMethod() {}
}

获取特定的声明方法(包括私有方法)

使用 Class.getDeclaredMethod(String name, Class<?>... parameterTypes) 可以获取类中声明的特定方法,包括私有方法。

public class ReflectionExample {
    public static void main(String[] args) {
        try {
            Class<?> clazz = SampleClass.class;
            Method method = clazz.getDeclaredMethod("privateMethod");
            System.out.println("Declared Method Name: " + method.getName());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

class SampleClass {
    private void privateMethod() {}
}

调用方法

调用无参数方法

public class ReflectionExample {
    public void sayHello() {
        System.out.println("Hello, World!");
    }

    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> clazz = ReflectionExample.class;
            
            // 创建类的实例
            Object instance = clazz.getDeclaredConstructor().newInstance();
            
            // 获取方法对象
            Method method = clazz.getMethod("sayHello");
            
            // 调用方法
            method.invoke(instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

调用带参数的方法

public class ReflectionExample {
    public void greet(String name) {
        System.out.println("Hello, " + name);
    }

    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> clazz = ReflectionExample.class;
            
            // 创建类的实例
            Object instance = clazz.getDeclaredConstructor().newInstance();
            
            // 获取方法对象,指定参数类型
            Method method = clazz.getMethod("greet", String.class);
            
            // 调用方法,传递参数
            method.invoke(instance, "Alice");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

调用私有方法

public class ReflectionExample {
    private void secretMethod() {
        System.out.println("This is a secret method!");
    }

    public static void main(String[] args) {
        try {
            // 获取类的Class对象
            Class<?> clazz = ReflectionExample.class;

            // 创建类的实例
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // 获取私有方法对象
            Method method = clazz.getDeclaredMethod("secretMethod");

            // 设置方法为可访问
            method.setAccessible(true);

            // 调用方法
            method.invoke(instance);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
posted @ 2024-11-01 17:22  Jacob-Chen  阅读(71)  评论(0)    收藏  举报