Java 基础2 - 反射
反射
Class
一般情况下,新建一个对象时可以在程序运行阶段之前就明确知道它的具体类型、属性等信息,然后使用 new
关键字进行生成,而反射这种手段是发生在运行的时候,而且是不知道这些信息的,需要借助于 Class
这个类来完成对象的生成。
每个已经加载的类在内存中都有一份它的信息,每个对象都有指向它的所属类信息的引用,类信息对应的类就是 java.lang.Class
。
Object
有一个方法可以获取对象的 Class
对象:
public final native Class<?> getClass()
因为这个方法本身不知道具体是个什么类型,所以用了个泛型通配符,如果用的时候知道具体类名,可以手动写明类型:
Class<People> class = People.class;
接口也有 Class
对象:
Class<Comparable> class = Comparable.class;
基本类型没有 getClass()
方法,但有 Class
对象,注意泛型参数就是包装类:
Class<Integer> intClass = int.class;
Class<Double> doubleClass = double.class;
...
数组:
Class<? extends String[]> strArrClass = (new String[3]).getClass();
Class<? extends int[][]> intArrsClass = (new int[3][3]).getClass();
枚举:
enum SIZE {
SMALL, BIG
};
Class<SIZE> class = SIZE.class;
根据类名直接加载 Class
(可能抛出异常 ClassNotFoundException
):
Class<?> class = Class.forName("java.util.HashMap");
使用 Class
获取信息
-
名称信息
其实就是获取类名,有以下几种方法:
public String getName(); public String getSimpleName(); public String getCanonicalName(); public String getPackage();
-
字段信息
Class 获取字段的方法:
// 返回所有的public字段,包括父类的 public Field[] getFields() throws SecurityException // 返回本类的所有字段,包括非 public 的,但不包括父类 public Field[] getDeclaredFields() throws SecurityException // 返回本类或父类中指定名称的字段 public Field getField(String name) // 返回本类中声明指定名称的字段 public Field getDeclaredField(String name)
Field 获取字段信息的方法:
// 获取字段名称 public String getName() // 是否当前程序可读 public boolean isAccessible() // 修改是否可读,以支持访问非 public 字段 public void setAccessible(boolean flag) throws SecurityException // 读取值,Obj就是被读取的目标对象 public Object get(Object obj) // 设置值,Obj就是被写入的目标对象 public void set(Object obj, Object value)
-
方法信息
Class
类获取方法信息的方法跟获取字段信息的方法差不多,见名知意。有个特别点的方法需要留意下:public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
对于
invoke
方法,如果这个Mehtod
是个静态方法,obj
就会被忽略,可以为null
,args
也可以为null
,也可以为一个空数组,方法调用的返回值被包装为Object
返回,如果实际方法调用抛出异常,异常会被包装为InvocationTargetException
重新抛出,可以通过getCause()
方法查看原异常。 -
创建对象和构造方法
Class
有个newInstance()
方法来创造新对象,它默认调用无参的public
构造函数,如果没有,就会抛出异常。Class
还提供了getConstructors()
来查看某个类有什么构造函数。 -
泛型
有些类是使用了泛型的,有以下几种方式支持读取类的泛型信息:
Class
:public TypeVariable<Class<T>>[] getTypeParameters()
Field
:public Type getGenericType()
Method
:public Type getGenericReturnType() public Type[] getGenericParameterTypes() public Type[] getGenericExceptionTypes()
Constructor
:public Type[] getGenericParameterTypes() public Type[] getGenericExceptionTypes()
-
类型检查与转换
instanceof
关键字可以判断某个对象是不是某个类的实例,instanceof
后面的类型是在代码中确定的,如果要检查的类型是动态的/运行前不确定的,可以使用Class
提供的isInstance()
来判断。代码中类型转换一般会在值的左边以
(类型)值
的形式做转换 ,这个类型也是提前知道的,如果是不确定的,可以使用Class
提供的cast()
方法来做转换。可以使用
Class
提供的isAssignableFrom()
来判断某个对象能不能赋值给某种类的变量。 -
Class 的类型信息
判断是否是数组、接口、基本类型、枚举、注解、内部类等类型。
-
类的声明信息
获取修饰符、用了什么注解、实现了哪些接口、等信息。
-
类的加载
// 使用系统类加载器(也叫应用程序类加载器)加载 public static Class<?> forName(String className) throws ClassNotFoundException // 使用指定的加载器加载 public static Class<?> forName(String name, boolean initialize, ClassLoader loader)
根据类名加载类就用
forName()
方法,ClassLoader
见后文:类加载器。 -
数组
数组类型有个方法可以获取元素类型:
public native Class<?> getComponentType()
还有个专门的类
Array
可以用于创建数组对象以及对数组进行访问。 -
枚举
枚举类型有个方法可以获取所有枚举常量:
public T[] getEnumConstants();
本文作者:遥遥领先
本文链接:https://www.cnblogs.com/nyfblog/p/16519122.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步