反射
反射机制
1、允许程序在执行期间借助 Reflection API 取得任何类的内部消息
2、加载完类之后,在堆中产生一个 Class 类型对象
3、一个类只有一个 Class 对象,该对象包含类的完整结构信息
反射相关的类
1、java.lang.Class<T>:Class 对象表示某个类加载后在堆中的对象
2、java.lang.reflect.Method:Method 对象表示某个类的方法
3、java.lang.reflect.Field:Field 对象表示某个类的成员变量
4、java.lang.reflect.Constructor<T>:Constructor 对象表示某个类的构造器
反射暴破
1、反射调用优化:关闭访问检查,提高反射效率
2、Method、Field、Constructor 继承 AccessibleObject,AccessibleObject 定义 setAccessible 方法
3、将调用方法的对象的 accessible 标志设置为指定的 boolean 值,true 表示反射对象应该在使用时抑制 Java 语言访问检查,false 表示反射的对象应该强制执行 Java 语言访问检查
public void setAccessible(boolean flag) throws SecurityException
Class 类
1、继承 Object 类,该类对象是系统通过类加载器(Classloader 类)的 loadClass 方法创建
2、类只加载一次,所以堆中类的 Class 对象只有一个
3、每个类的对象都知道自身属于哪个 Class 类对象生成的
4、通过 Class 对象的 API 得到一个类的完整结构
5、类的字节码(.class)二进制数据(类的元数据)储存在方法区
获取 Class 类对象
1、已知一个类的全类名,且该类在类路径下,通过 Class 类的静态方法 forName 获取
Class cls = Class.forName("类的全类名");
(1)应用场景:配置文件读取类的全路径,加载类
2、已知具体的类,通过该类的 class 获取
Class cls = 类名.class;
(1)最安全,性能最高
(2)应用场景:用于传递参数
3、已知某个类的实例,调用该实例的 getClass 方法获取
Class cls = 对象名.getClass();
(1)应用场景:通过已创建的对象,获取 Class 对象
4、通过类的加载器获取
ClassLoader classLoader = 对象名.getClass().getClassLoader();
Class cls = classLoader.loadClass("类的全类名");
5、基本数据类型、包装类获取的 Class 对象是同一个,因为有自动装箱、拆箱机制
(1)基本数据类型
Class<包装类> cls = 基本数据类型.class;
(2)包装类
Class<包装类> cls = 包装类.TYPE;
存在 Class 对象的类型
1、外部类
2、成员内部类、静态内部类、局部内部类、匿名内部类
3、interface 接口、数组、annotation 注解、enum 枚举、基本数据类型、Class、void
类加载
1、静态加载:编译阶段加载相关类,若不存在该类,依赖性强
2、动态加载:运行阶段加载相关类,若运行阶段时不调用此类,则不报错,降低依赖性
3、类加载时机:静态加载:(1)(2)(3);动态加载:(4)
(1)创建对象
(2)子类被加载,父类也加载
(3)调用类中的静态成员(static final 不会导致类加载)
(4)通过反射
.java 源文件 ->(javac 编译)-> .class 字节码文件 ->(java 运行)-> 加载 -> 连接:验证、准备、解析 -> 初始化
1、加载:由类加载器完成,字节码从不同数据源转为二进制字节流加载到内存,字节码文件储存在方法区,创建 Class 对象储存在堆
2、连接:类的二进制数据合并到 JRE中
(1)验证:确保 .class 文件字节流所含信息符合当前虚拟机的要求,且不危害虚拟机自身安全;文件格式验证、元数据验证、字节码验证、、符号引用验证;可以使用 -Xvertify:none 参数关闭大部分类验证措施,缩短虚拟机加载时间
(2)准备:JVM 对静态变量、分配内存并默认初始化(数据类型的默认初始值),在方法区分配所使用的内存
(3)解析:虚拟机将常量池内符号引用替换为直接引用
3、初始化:执行 <clinit>() 方法,真正执行类中定义的 Java 程序代码
(1)<clinit>() 方法由编译器按语句在源文件出现顺序,依次自动收集类中所有静态变量赋值动作、静态代码块中语句,并合并
(2)虚拟机保证一个类的 <clinit>() 方法在多线程环境中被正确的加锁、同步
(3)若多线程同时初始化一个类,只有一个线程执行该类 <clinit>() 方法,其他线程阻塞,直到活动线程执行完毕
Modifier 类
public static final int PUBLIC = 0x00000001;
public static final int PRIVATE = 0x00000002;
public static final int PROTECTED = 0x00000004;
public static final int STATIC = 0x00000008;
public static final int FINAL = 0x00000010;
public static final int SYNCHRONIZED = 0x00000020;
public static final int VOLATILE = 0x00000040;
public static final int TRANSIENT = 0x00000080;
public static final int NATIVE = 0x00000100;
public static final int INTERFACE = 0x00000200;
public static final int ABSTRACT = 0x00000400;
public static final int STRICT = 0x00000800;
static final int BRIDGE = 0x00000040;
static final int VARARGS = 0x00000080;
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION = 0x00002000;
static final int ENUM = 0x00004000;
static final int MANDATED = 0x00008000;
通过反射获取类的结构信息
1、Class 类
(1)返回指定注释类型的注释,包含继承的注解,若此注解类型不存在,返回 null
public <A extends Annotation> A getAnnotation(Class<A> annotationClass)
(2)以数组形式返回所有注释,包含继承的注解
public Annotation[] getAnnotations()
(3)返回一个 Class 数组,包含本类及父类的所有 public 内部类和接口的 Class 对象,若为基本数据类型、数组、void、此类对象没有 public 类或接口,则返回长度为 0 的数组
public Class<?>[] getClasses()
(4)返回类的类加载器
public ClassLoader getClassLoader()
(5)根据参数类型,返回本类的 public 构造器 Consrtructor 对象
public Constructor<T> getConstructor(类<?>... parameterTypes) throws NoSuchMethodException, SecurityException
(6)返回一个包含 Constructor 对象的数组,包含本类的所有 public 类函数,若为基本数据类型、数组、void、此类对象没有 public 构造器,返回长度为 0 的数组
public Constructor<?>[] getConstructors() throws SecurityException
(7)返回指定注释类型的注释,不包含继承的注解,若此注解类型不存在,返回 null
public <A extends Annotation> A getDeclaredAnnotation(Class<A> annotationClass)
(8)以数组形式返回所有注释,不包含继承的注解
public Annotation[] getDeclaredAnnotations()
(9)返回一个 Class 数组,包含本类所有内部类和接口的 Class 对象,若为基本数据类型、数组、void、此类对象没有 public 类或接口,则返回长度为 0 的数组
public Class<?>[] getDeclaredClasses() throws SecurityException
(10)返回指定参数类型的 Consrtructor 对象
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
(11)返回所有构造器 Consrtructor 对象数组
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
(12)返回指定 name 的 Field 对象
public Field getDeclaredField(String name) throws NoSuchFieldException, SecurityException
(13)返回本类所有属性 Field 对象数组,如果此类对象没有声明字段、数组、基本数据类型、void,则此方法返回长度为0的数组
public Field[] getDeclaredFields() throws SecurityException
(14)根据指定的名称和参数,返回本类 Method 对象
public Method getDeclaredMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
(15)返回本类所有方法 Method 对象数组
public Method[] getDeclaredMethods() throws SecurityException
(16)返回该类的外部类 Class 对象,若不为内部类、或为匿名内部类、数组、基本数据类型、void,返回 null
public Class<?> getDeclaringClass() throws SecurityException
(17)返回该类的外部类 Class 对象,若该类是顶级类,则此方法返回 null
public Class<?> getEnclosingClass() throws SecurityException
(18)返回该内部类的 Constructor 对象,若不为内部类,返回 null
public Constructor<?> getEnclosingConstructor() throws SecurityException
(19)返回该内部类的 Method 对象,若不为内部类,返回 null
public Method getEnclosingMethod() throws SecurityException
(20)返回此枚举类的元素数组,如果此 Class 对象不表示枚举类型,则返回null
public T[] getEnumConstants()
(21)返回指定 name 的一个 Field 对象,包括本类及父类的 public 属性
public Field getField(String name) throws NoSuchFieldException, SecurityException
(22)返回 Field 对象数组,包括本类及父类的所有 public 属性
public Field[] getFields() throws SecurityException
(23) 返回此 Class 对象表示的类或接口直接实现的接口的 Type 数组
public Type[] getGenericInterfaces()
(24)返回该 Class 对象直接父类的 Type,若为 Object类、接口、基本数据类型、void,则返回 null,若为数组,则返回 Object 类的 Class 对象
public Type getGenericSuperclass()
(25)返回此 Class 对象表示的类或接口实现的接口 Class 对象数组
public Class<?>[] getInterfaces()
(26)根据 name、参数类型,返回 Method 对象,限本类及父类所有 public 方法
public Method getMethod(String name, Class<?>... parameterTypes) throws NoSuchMethodException, SecurityException
(27)返回 Method 对象数组,包含本类及父类所有 public 方法
public Method[] getMethods() throws SecurityException
(28)返回全类名
public String getName()
(29)返回包名
public Package getPackage()
(30)返回简单类名
public String getSimpleName()
(31)返回该 Class 对象直接父类的 Type,若为 Object类、接口、基本数据类型、void,则返回 null,若为数组,则返回 Object 类的 Class 对象
public Class<? super T> getSuperclass()
(32)以 int 形式返回修饰符,多个修饰符则相加
public int getModifiers()
2、Field 类
(1)返回属性名
public String getName()
(2)返回属性类型的 Class 对象
public Class<?> getType()
(3)以 int 形式返回修饰符,多个修饰符则相加
public int getModifiers()
3、Method 类
(1)返回方法名
public String getName()
(2)以 int 形式返回修饰符,多个修饰符则相加
public int getModifiers()
(3)获取方法返回数据类型的 Class 对象
public Class<?> getReturnType()
(4)返回方法的形参 Class 对象数组,以声明顺序排序,若没有参数,则返回长度为 0 的数组
public Class<?>[] getParameterTypes()
4、Constructor 类
(1)返回此构造函数的名称
public String getName()
(2)以 int 形式返回修饰符,多个修饰符则相加
public int getModifiers()
(3)返回构造器的形参 Class 对象数组,以声明顺序排序,若没有参数,则返回长度为 0 的数组
public Class<?>[] getParameterTypes()
通过反射创建对象
1、调用 Class 类中方法
(1)调用类中无参构造器,获取对应类的对象,要求构造器为 public
Class对象.newInstance();
(2)根据参数的 Class 对象,获取 public 构造器
public Constructor<T> getConstructor(Class<?>... parameterTypes)
(3)根据参数的 Class 对象,获取构造器
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
2、调用 Constructor 类中方法
(1)暴破构造器的封装性,即可以调用 private 构造器
Constructor对象.setAccessible(true);
(2)根据参数列表创建对象,若没有暴破,则要求为 public 构造器
Constructor对象.newInstance(参数列表);
通过反射访问属性
1、暴破
Field对象.setAccessible(true);
2、设置属性:将 obj 对象的属性(该 Field 对象)设为 value
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException
3、获取属性:返回 obj 对象的属性(该 Field 对象)
public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException
4、若属性为 static,set、get 方法中的 obj 参数传入 null
通过反射访问方法
1、暴破
Method对象.setAccessible(true);
2、访问方法:传入 args 参数,调用 obj 对象的方法(该 Method 对象)
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException
(1)若为 static 方法,obj 参数传入 null
(2)若方法存在返回值,编译类型为 Object,运行类型与方法定义的返回数据类型一致
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· 没有源码,如何修改代码逻辑?
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战