java反射笔记

反射(reflect)

1. Class对象

1.1 什么是Class对象

当JVM加载某个class文件的时候,会自动创建一个唯一的Class对象(注意:由同一个类加载器加载的class文件),这个Class对象包含了整个class类的信息(例如:类的名称、访问修饰符、字段、字段描述、方法等等一切信息)。当使用new关键字创建这个类的实例时,jvm都会使用这个Class对象来创建类的实例。

1.1 获取Class对象方式

方式说明
Test.class 通过类名.class直接获取
t1.getClass() 通过对象的getClass()方法获取
Class.forName("...") 使用Class类的forName静态方法获取,参数给的是完整类名(包名+类名)

2. 反射

2.1 什么是反射

所谓的反射,是在程序运行时动态获得任何一个Class对象的成员信息(类信息、字段、构造方法、成员方法等),并且能在运行时依据某个Class对象创建当前类的实例。

2.2 Class常用API

方法说明
newInstance() 创建类实例
getName() 获取类的完整类名
getSimpleName() 获取类的简单类名
getPackage() 获取类对应的包信息
getSuperclass() 获取父类的Class对象
getInterfaces() 获取实现的所有接口
getClassLoader() 获取当前类的类加载器
getConstructor(..) 获取公共且明确参数类型的构造方法
getDeclaredConstructor(..) 获取受保护且明确参数类型的构造方法
getConstructors() 获取所有公共的构造方法
getDeclaredConstructors() 获取所有(包括受保护)的构造方法
getField(..) 根据字段名称获取某一个公共的字段
getDeclaredField(..) 根据字段名称获取当前类某一个的字段(包括受保护的)
getFields() 获取所有公共的字段,包括继承自父类的公共字段
getDeclaredFields 获取当前类所有字段,包括受保护的(不包括继承父类的字段)
getMethod(..) 根据方法名以及参数类型获取一个公共的方法
getDeclaredMethod(..) 根据方法名以及参数类型获取当前类的一个受保护的方法
getMethods() 获取所有公共的方法(包括继承自父类的公共方法)
getDeclaredMethods() 获取当前类的所有方法,包括受保护的(不包括继承父类的方法)
isAnnotation() 此Class是否是一个注解
isAnnotationPresent(..) 当前Class时是否定义了某个注解
getAnnotation(..) 获取当前类上定义的某个注解
getAnnotations() 获取当前类上定义的所有注解
isEnum() 此Class是否是一个枚举
isArray() 此Class是否是一个数组类型
isInterface() 此Class是否是一个接口
... 其他API请参照官方文档
public class TestClass {
​
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("edu.nf.reflect.Users");
        //通过Class对象来创建实例,当前类必须提供一个公开并且无参的构造方法
        Users user = (Users) clazz.newInstance();
        //获取类的完整类名
        System.out.println(clazz.getName());
        //获取类的简单类名
        System.out.println(clazz.getSimpleName());
        //获取类所在的包名
        System.out.println(clazz.getPackage().getName());
        //获取当前类的父类的Class
        System.out.println(clazz.getSuperclass());
        //获取当前类实现的所有接口
        System.out.println(clazz.getInterfaces());
        //获取加载这个类的类加载器
        System.out.println(clazz.getClassLoader());
        //获取公共并且参数类型为String的构造方法
        clazz.getConstructor(String.class);
        //获取私有并且参数为int类型的构造方法
        clazz.getDeclaredConstructor(Integer.TYPE);
        //获取所有公共的构造方法
        Constructor[] consArray1 = clazz.getConstructors();
        //获取所有构造方法,包括公共和是有的
        Constructor[] consArray2 = clazz.getDeclaredConstructors();
        //获取某一个公共的字段,参数指定字段的名字
        Field f1 = clazz.getField("address");
        System.out.println(f1.getName());
        //获取某一个受保护的字段
        Field f2 = clazz.getDeclaredField("tel");
        System.out.println(f2.getName());
        System.out.println("-----------------------");
        //获取所有公共的字段,包括继承自父类的公共字段
        Field[] fieldArray1 = clazz.getFields();
        for (Field field : fieldArray1) {
            System.out.println(field.getName());
        }
        System.out.println("-----------------------");
        //获取所有字段,包括受保护的(不包括继承父类的字段)
        Field[] fieldArray2 = clazz.getDeclaredFields();
        for (Field field : fieldArray2) {
            System.out.println(field.getName());
        }
        System.out.println("-----------------------");
        //获取某一个公共的方法(第一个参数指定方法名,第二个参数指定方法参数的类型,这是一个可变参数,有多少个参数就要指定多少个类型)
        Method m1 = clazz.getMethod("say", String.class);
        System.out.println(m1.getName());
        //获取某一个受保护的方法
        Method m2 = clazz.getDeclaredMethod("call");
        System.out.println(m2.getName());
        System.out.println("-----------------------");
        //获取所有公共的方法(包括继承自父类的公共方法)
        Method[] methodArray1 = clazz.getMethods();
        for (Method method : methodArray1) {
            System.out.println(method.getName());
        }
        System.out.println("-----------------------");
        //获取本类的所有方法,包括受保护的(不包括父类的方法)
        Method[] methodArray2 = clazz.getDeclaredMethods();
        for (Method method : methodArray2) {
            System.out.println(method.getName());
        }
    }
}
​

 

2.3 Class对象中的成员

成员说明
Constructor 用于描述类的构造方法
Field 用于描述类的字段
Method 用于描述类的方法
Parameter 用于描述方法或构造方法的参数信息

2.3.1 Constructor常用API

API说明
getName() 获取当前构造方法的名称
getParameterCount() 获取构造方法的参数个数
getDeclaringClass() 获取声明此构造方法的Class类
setAccessible(..) 设置访问开关
newInstance(..) 使用当前的Constructor构建实例
... 其他API请参照官方文档
public class TestCons {
    public static void main(String[] args) throws Exception{
        //加载Users的class信息,并构建Class对象
        Class<?> clazz = Class.forName("edu.nf.reflect.Users");
        //通过class对象访问构造方法信息,
        // 根据构造方法的参数类型获取某一个公共的构造方法
        Constructor cons1 = clazz.getConstructor(int.class);
        // 访问受保护的构造方法
        Constructor cons2 = clazz.getDeclaredConstructor(int.class);
        //构造方法的名称
        System.out.println(cons1.getName());
        //获取构造方法的参数个数
        System.out.println(cons1.getParameterCount());
        //获取定义这个构造方法的Class类
        System.out.println(cons1.getDeclaringClass());
        //通过构造方法来创建类的实例
        //由于构这个造方法是私有的,因此必须强制打开访问开关
        cons1.setAccessible(true);
        //然后通过newInstance方法来创建类的实例,并传入构造方法所需的参数
        Users user = (Users)cons1.newInstance(21);
        //获取所有的构造方法(包括私有和公有的)
        Constructor[] cons = clazz.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println("参数个数: "+con.getParameterCount());
        }
    }
}
 

2.3.2 Field常用API

API说明
getType() 获取当前字段类型
getName() 获取当前字段名称
get(..) 获取当前字段的值
set(..) 给当前字段赋值
setAccessible(..) 设置访问开关
... 其他API请参照官方文档
public class TestField {
​
    public static void main(String[] args) throws Exception{
        Class<?> clazz = Class.forName("edu.nf.reflect.Users");
        //创建类的实例
        Object instance = clazz.newInstance();
        //获取一个受保护的字段
        Field f = clazz.getDeclaredField("tel");
        //打开访问开关
        f.setAccessible(true);
        //给字段赋值(第一个参数指定当前类的实例,第二个参数是具体的值)
        f.set(instance, "123456");
        //取值(get方法的参数也是指定当前类的实例)
        System.out.println(f.get(instance));
        //获取字段的类型
        System.out.println(f.getType());
        //获取字段的名称
        System.out.println(f.getName());
    }
}

 

2.3.3 Method常用API

API说明
getName() 获取当前方法名称
getReturnType() 获取当前方法的返回值
getParameterCount() 获取当前方法参数的个数
getParameters() 获取当前方法的参数对象
getParameterTypes() 获取当前方法的所有参数类型
setAccessible(..) 设置访问开关
invoke(..) 回调当前的method
... 其他API请参照官方文档
public class TestMethod {
​
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("edu.nf.reflect.Users");
        //构建当前类的实例
        Object instance = clazz.newInstance();
        //获取受保护的call方法
        Method method = clazz.getDeclaredMethod("call", String.class);
        //获取方法的名称
        System.out.println(method.getName());
        //获取方法的返回值类型
        System.out.println(method.getReturnType());
        //获取方法参数的个数
        System.out.println(method.getParameterCount());
        //获取方法的所有参数对象
        System.out.println(method.getParameters());
        //获取方法中所有参数的类型
        Class<?>[] paramsType = method.getParameterTypes();
        for (Class<?> aClass : paramsType) {
            System.out.println(aClass);
        }
        //调用当前方法(第一个参数是当前类的实例,第二个参数开始是方法所需的参数)
        //invoke方法返回的是当前调用的方法的返回值
        //这个方法是受保护的,因此需要先打开访问开关
        method.setAccessible(true);
        Object returnValue = method.invoke(instance, "12345678");
        System.out.println(returnValue);
    }
}
​

 

2.3.4 Parameter常用API

API说明
getType() 获取参数类型
getName() 获取参数的名称(说明:JDK8默认编译的时候是不会将参数名信息保存在字节码中,如果想要获取参数名,那么在编译时就需要加上编译参数 ,如:javac -parameters Users.java)
... 其他API请参照官方文档

public class TestParameter {
​
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("edu.nf.reflect.Users");
        //先获取指定的受保护的方法
        Method callMethod = clazz.getDeclaredMethod("call", String.class);
        //获取该方法的参数信息
        Parameter[] params = callMethod.getParameters();
        for (Parameter param : params) {
            //获取参数的类型
            System.out.println(param.getType());
            //获取参数的名称(在JDK8之前是没有办法获取参数名的,必须通过第三方字节码工具来获取)
            //JDK8默认编译的时候是不会讲参数名信息保存在字节码中
            //如果想要获取参数名,那么在编译时就需要加上编译参数
            //如:javac -parameters Users.java
            System.out.println(param.getName());
        }
    }
}
 
原文地址:https://www.cnblogs.com/hhmm99/p/9551514.html