Java反射学习

概述

Java 反射机制可以让我们在编译期(Compile Time)之外的运行期(Runtime)检查类,接口,变量以及方法的信息. 反射还可以让我们在运行期实例化对象,调用方法,获取/设置变量的值.Java反射相关的类主要在java.lang.reflect.*

Class 类

要获取类信息首先要获取到Class对象, Class类没有Public的构造方法,Class类的实例都是在JVM在加载类时通过调用ClassLoader的defineClass方法创建的.下面代码块是对Class的一些API的介绍直接看注释.

相反,Java虚拟机在加载类和调用类加载器中的{@code defineClass}方法时自动构造{@code Class}对象。

package tiny.wong;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

public class Main {
    public static void main(String[] args) {
        // 1. 获取Class对象
        System.out.println("------------------------->>>>>> Class对象");
        // 1.1 使用类名.class获取Class对象
        Class myObjectClass1 = MyObject.class;
        try {
            // 1.2 使用全类名(包括包名)字符串来获取Class对象.
            Class myObjectClass2 = Class.forName(MyObjectClassStringName);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(myObjectClass1.getName());

        // 2. 获取类名字符串
        System.out.println("------------------------->>>>>> 类名");
        // 2.1 获取全类名字符串(包含包名:tiny.wong.Main$MyObject)
        System.out.println("getName=" + myObjectClass1.getName());
        // 2.2 获取类名(不包含包名,外部类名:MyObject)
        System.out.println("getSimpleName=" + myObjectClass1.getSimpleName());
        // 2.3 返回Java语言规范定义的基础类的规范名称. (内部类使用"."而不是"$",其实可以简单理解为代码中定义变量时使用的名称: tiny.wong.Main.MyObject)
        System.out.println("getCanonicalName=" + myObjectClass1.getCanonicalName());

        // 3. 获取访问修饰符
        System.out.println("------------------------->>>>>> Java访问修饰符");
        // 返回该类或接口的Java语言修饰符所对应的整数编码. 具体编码见: java.lang.reflect.Modifier
        int modifiers = myObjectClass1.getModifiers();
        System.out.println("isPublic=" + Modifier.isPublic(modifiers));

        // 4. 获取包信息
        System.out.println("------------------------->>>>>> 获取包信息");
        // 获取Package信息. tiny.wong
        Package aPackage = myObjectClass1.getPackage();
        System.out.println("Package=" + aPackage.getName());

        // 5. 获取父类Class
        System.out.println("------------------------->>>>>> 获取父类Class");
        Class superclass = myObjectClass1.getSuperclass();
        System.out.println("SupperPackage=" + superclass.getName());

        // 6. 获取实现的接口
        System.out.println("------------------------->>>>>> 获取实现的接口");
        Class[] interfaces = myObjectClass1.getInterfaces();

        // 7. 获取类的构造方法
        System.out.println("------------------------->>>>>> 获取类的构造方法");
        // 获取所有Public的构造器.
        Constructor[] constructors = myObjectClass1.getConstructors();

        // 8. 获取方法
        // 8.1 获取类的所有Public方法, 包括父类的.
        Method[] methods = myObjectClass1.getMethods();
        // 8.2 获取当前类定义的所有方法(不仅仅是Public), 不包括父类的方法
        Method[] declaredMethods = myObjectClass1.getDeclaredMethods();
        try {
            // 8.3 通过方法名称和参数类型来获取方法.(含父类)
            Method methodName = myObjectClass1.getMethod("methodName", null);
            // 8.3 通过方法名称和参数类型来获取方法.(不含父类)
            Method thisMethodName = myObjectClass1.getDeclaredMethod("thisMethodName", null);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        // 9. 获取成员变量
        // 9.1 获取所有的Public成员变量包括父类的.
        Field[] fields = myObjectClass1.getFields();
        // 9.2 获取当前类定义的所有的(包含private,protected)成员变量, 不包括父类的.
        Field[] declaredFields = myObjectClass1.getDeclaredFields();
        try {
            // 9.3 通过成员变量名来获取成员变量(包括父类)
            Field fieldName = myObjectClass1.getField("FieldName");
            // 9.4 通过成员变量名来获取成员变量(不含父类)
            Field thisClassFieldName = myObjectClass1.getDeclaredField("ThisClassFieldName");
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

        // 10. 获取所有注解
        // 10.1 获取所有注解(含父类)
        Annotation[] annotations = myObjectClass1.getAnnotations();
        // 10.2 获取当前类注解(不含父类)
        Annotation[] declaredAnnotations = myObjectClass1.getDeclaredAnnotations();
        // 10.3 根据注解类型获取注解
        Annotation annotation = myObjectClass1.getAnnotation(null);
        Annotation declaredAnnotation = myObjectClass1.getDeclaredAnnotation(null);

        // 11. 类型判断相关方法
        myObjectClass1.isAnnotation();
        myObjectClass1.isArray();
        myObjectClass1.isEnum();
        myObjectClass1.isInstance(null);
        myObjectClass1.isInterface();

        // 12. 创建对象
        try {
            // 使用默认构造方法创建对象
            MyObject instance = (MyObject) myObjectClass1.newInstance();
            // 有参数的可以使用构造器的方法
            // constructors[0].newInstance(...)
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }


    }

    public static final String MyObjectClassStringName = "tiny.wong.Main$MyObject";
    public static class MyObject implements MyInterface {

    }

    public interface MyInterface {
    }

}
  • Java的访问修饰符被映射成整数类型, 由java.lang.reflect.Modifier类来同一管理. Modifier类提供了一系列静态方法用来判断类和成员变量的访问修饰符. 主要的静态方法如下:

    Modifier.isAbstract(int modifiers);
    Modifier.isFinal(int modifiers);
    Modifier.isInterface(int modifiers);
    Modifier.isNative(int modifiers);
    Modifier.isPrivate(int modifiers);
    Modifier.isProtected(int modifiers);
    Modifier.isPublic(int modifiers);
    Modifier.isStatic(int modifiers);
    Modifier.isStrict(int modifiers);
    Modifier.isSynchronized(int modifiers);
    Modifier.isTransient(int modifiers);
    Modifier.isVolatile(int modifiers);
    
  • 注意getXXXgetDeclaredXXX的区别.

    • getMethods()getFields() : 获取当前类和父类中的所有的Public方法/成员变量. 是无法获取到private或者protected修饰的方法/成员变量的.
    • getDeclaredMethods()getDeclaredFields(): 获取当前类中(不包括父类)的所有的private,public,protected修饰的方法/成员变量.
    • getMethod(""),getField(""),getDeclaredMethod(""),getDeclaredField("") 也是符合上述规则.

Java构造器(Constructor)

利用Java反射机制可以在运行时访问类构造器信息, 并且可以在运行时创建类的实例对象, 这是功能都是封装在java.lang.reflect.Constructor类中的.

获取Constructor对象

通过Class类的getConstructors() 方法可以获取到类的所有的Public修饰的构造器.

// 创建一个类
public static class MyObject {
	// protected 无法获取
    MyObject() {

    }
	// public 可以获取
    public MyObject(String name) {

    }
	// private 无法获取
    private MyObject(int age) {

    }
}
// 获取Class对象
Class<MyObject> clazz = MyObject.class;
// 1. 获取所有的Public构造器
Constructor<?>[] constructors = clazz.getConstructors();
// Constructors=[public tiny.wong.ConstructorTest$MyObject(java.lang.String)]
System.out.println("Constructors="+ Arrays.toString(constructors));

// 2. 获取指定参数类型的构造器
Constructor constructor = clazz.getConstructor(new Class[]{String.class});

参数类型和实例对象的创建

Constructor constructor = constructors[0];
// 参数个数
int parameterCount = constructor.getParameterCount();
// 参数类型
Class[] parameterTypes = constructor.getParameterTypes();
// 访问修饰符
int modifiers = constructor.getModifiers();
// 获取方法注解
Annotation[] annotations = constructor.getAnnotations();
Annotation annotation = constructor.getAnnotation(null);
// 获取参数注解
constructor.getParameterAnnotations();

// 创建对象
try {
	// newInstance 的参数是可变参数列表.
    MyObject name = (MyObject) constructor.newInstance("name");
} catch (InstantiationException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

Java 成员变量(Field)

使用 Java 反射机制可以在运行期检查一个类的成员变量信息或者获取/设置变量的值。通过使用 java.lang.reflect.Field 类就可以实现上述功能

首先是访问普通属性

Son son = new Son();
Class clazz = Son.class;
// 1.1 获取所有的Public方法(包含父类)
Field[] fields = clazz.getFields();
// 1.2 获取指定的名称的Public Field
try {
    Field theField = clazz.getField("fieldName");
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}
// 1.3 获取当前类的所有成员变量(不含父类)
Field[] declaredFields = clazz.getDeclaredFields();
// 1.4 获取当前类的指定成员变量(不含父类)
try {
    Field theField1 = clazz.getDeclaredField("fieldName");
} catch (NoSuchFieldException e) {
    e.printStackTrace();
}

// 2. Filed 的相关操作
Field field = fields[0];
// 2.1 变量名字
String filedName = field.getName();
// 2.2 变量类型
Class<?> type = field.getType();
try {
    // 2.3 变量值
    Object o = field.get(son);
    // 2.4 设置成员变量的值
    field.set(son, null);
} catch (IllegalAccessException e) {
    e.printStackTrace();
}
// 2.5 变量注解
Annotation[] annotations = field.getAnnotations();
Annotation[] declaredAnnotations = field.getDeclaredAnnotations();
Annotation annotation = field.getAnnotation(null);
// 2.6 变量的访问修饰符
int modifiers = field.getModifiers();

访问私有成员变量
私有成员变量只能通过getDeclaredFields() 或者 getDeclaredField("filedName")来获取到.

Son son = new Son();
Class clazz = Son.class;
// 获取私有属性
try {
    Field name = clazz.getDeclaredField("name");
    // 调用 setAccessible()方法会关闭指定类 Field 实例的反射访问检查
    // 如果不进行设置, 可能会访问不到.
    name.setAccessible(true);
    // 获取属性值
    Object value = name.get(son);
    // 设置属性值
    name.set(son, null);
} catch (NoSuchFieldException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
}

Java 方法(Method)

Son son = new Son();
Class clazz = Son.class;
// 1. 获取Method对象.
// 1.1 获取所有的Public方法(含父类)
Method[] methods = clazz.getMethods();
// 1.2 获取当前类所有的方法(不含父类)
Method[] declaredMethods = clazz.getDeclaredMethods();
// 1.3 获取指定方法.规则和上面一样.
try {
    Method method = clazz.getMethod("method", null);
    Method method1 = clazz.getDeclaredMethod("method", null);
} catch (NoSuchMethodException e) {
    e.printStackTrace();
}
Method method = methods[0];
// 2. 方法名
String name = method.getName();
// 3. 方法返回值类型
Class<?> returnType = method.getReturnType();
// 4. 方法参数类型
Class<?>[] parameterTypes = method.getParameterTypes();
// 5. 方法调用
try {
    method.invoke(son, null);
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}
// 6. 方法注解
Annotation[] annotations = method.getAnnotations();
Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
method.getDeclaredAnnotation(null);

访问私有方法

Son son = new Son();
Class clazz = Son.class;
try {
    // 获取私有方法, 只能通过getDeclaredMethod,不能使用getMethod因为后者只能获取到Public修饰的方法.
    Method test = clazz.getDeclaredMethod("test", new Class[]{String.class});
    // 设置访问屏蔽反射访问检查
    test.setAccessible(true);
    // 调用方法
    test.invoke(son, "test");

} catch (NoSuchMethodException e) {
    e.printStackTrace();
} catch (IllegalAccessException e) {
    e.printStackTrace();
} catch (InvocationTargetException e) {
    e.printStackTrace();
}

Getters和Setters

使用 Java 反射你可以在运行期检查一个方法的信息以及在运行期调用这个方法,使用这个功能同样可以获取指定类的 getters 和 setters. 但是需要自己来实现判断逻辑.

public class GetterAndSetterDemo {
    public static void testGetterAndSetter() {
        Son son = new Son();
        Class clazz = Son.class;
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println("MName=" + method + " is Setter=" + isSetter(method));
            System.out.println("MName=" + method + " is Getter=" + isGetter(method));
        }
    }

    public static boolean isGetter(Method method){
        if (!method.getName().startsWith("get")) {
            return false;
        }
        if (method.getParameterTypes().length != 0) {
            return false;
        }
        if (void.class.equals(method.getReturnType())) {
            return false;
        }
        return true;
    }

    public static boolean isSetter(Method method) {
        if (!method.getName().startsWith("set")) {
            return false;
        }
        if (method.getParameterTypes().length != 1) {
            return false;
        }
        if (!void.class.equals(method.getReturnType())) {
            return false;
        }
        return true;
    }
}

Java注解

Son son = new Son();
Class clazz = Son.class;
// 1. 方法注解
Method[] methods = clazz.getMethods();
Annotation[] annotations = methods[0].getAnnotations();
for (Annotation anno : annotations) {
    if (anno instanceof Deprecated) {
        System.out.println("Method Deprecated");
    }
}
// 2. 变量注解
Field[] fields = clazz.getFields();
Annotation[] annotations1 = fields[0].getAnnotations();
for (Annotation anno : annotations1) {
    if (anno instanceof Deprecated) {
        System.out.println("Method Deprecated");
    }
}

Java数组

public static void testArray() {
    // Java 反射机制通过 java.lang.reflect.Array 这个类来处理数组
    // 1. 创建一个数组
    int[] intArray = (int[]) Array.newInstance(int.class, 4);
    // 2. 设置数组元素值
    Array.set(intArray, 0, 0);
    Array.set(intArray, 1, 1);
    // 3. 获取元素值
    Array.get(intArray, 0);
    Array.get(intArray, 1);
    // 4. 获取数组的成员类型
    Class aClass = intArray.getClass();
    Class componentType = aClass.getComponentType();


    // 获取数组的Class
    Class clazz1 = String[].class;
    try {
        // 在JVM中I代表int, [ 表示是数组.比如 "[Ljava.lang.String;"
        Class clazz2 = Class.forName("[I");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    // 注意基本数据类型的Class不能直接用I或者int配合Class.forName来获取
}

参考链接: http://wiki.jikexueyuan.com/project/java-reflection

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值