Class类:
对象照镜子后可以得到的信息:
某个类的属性、方法和构造器、某个类到底实现了哪些接口。对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含 了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。
? Class本身也是一个类
? Class 对象只能由系统建立对象
? 一个加载的类在 JVM 中只会有一个Class实例
? 一个Class对象对应的是一个加载到JVM中的一个.class文件
? 每个类的实例都会记得自己是由哪个 Class 实例所生成
? 通过Class可以完整地得到一个类中的所有被加载的结构
? Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的 Class对象
Class类常用方法
获取Class类实例方法:
1)Class clazz = String.class
2)Class clazz = 某类实例.getClass();
3)Class clazz = Class.forName(“java.lang.String”); //最为常用
拥有Class对象的类型:
各种类 基本数据类型 接口 数组 枚举 注解
对于数组数组只要元素类型与维度一样,就是同一个Class
对这些基本类型Class延申参考https://www.cnblogs.com/jpfss/p/11382043.html
Class与class字节码的联系在类的加载阶段有体现:
加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时 数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的 过程需要类加载器参与。
三种类加载器ClassLoader:
引导类加载器:用C++编写的,是JVM自带的类加载器,负责Java平台核心库,用来装载核心类 库。该加载器无法直接获取
扩展类加载器:负责jre/lib/ext目录下的jar包或 – D java.ext.dirs 指定目录下的jar包装入工作库
系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工 作 ,是最常用的加载器
private Person(String name) { this.name = name; }
创建运行时类的对象:
1)无参构造器,类的构造器的访问权限需要足够:
直接调用Class对象的newInstance()方法,比较简单。
2)有参构造器,足够访问权限
先获取带有指定参数类型的构造器,在创建实例
Class clazz = Person.class; //1.通过反射,创建Person类的对象 Constructor cons = clazz.getConstructor(String.class,int.class); Object obj = cons.newInstance("Tom", 12); Person p = (Person) obj;
3)有参构造器,私有权限
private Person(String name) { this.name = name; }
使用反射,强行开放权限(注意 Declared 后面马上解释)
Constructor cons1 = clazz.getDeclaredConstructor(String.class); cons1.setAccessible(true); Person p1 = (Person) cons1.newInstance("Jerry");
调用运行时类指定结构:
i 调用指定方法:
通过反射,调用类中的方法,通过Method类完成。步骤:
1.通过Class类的getMethod(String name,Class…parameterTypes)方法取得 一个Method对象,并设置此方法操作时所需要的参数类型。
2.之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中 传递要设置的obj对象的参数信息。
getMethod 返回所有public方法, getDeclaredMethod返回所有方法。
Object invoke(Object obj, Object[] args)
说明:
1.Object 对应原方法的返回值,若原方法无返回值,此时返回null
2.若原方法若为静态方法,此时形参Object obj可为null
3.若原方法形参列表为空,则Object[] args为null
4.若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。
private String showNation(String nation){ System.out.println("我的国籍是:" + nation); return nation; }
Method showNation = clazz.getDeclaredMethod("showNation", String.class); showNation.setAccessible(true); String nation = (String) showNation.invoke(p1,"中国");//相当于String nation = p1.showNation("中国") System.out.println(nation);
ii 调用指定属性:
在反射机制中,可以直接通过Field类操作类中的属性,通过Field类提供的set()和 get()方法就可以完成设置和取得属性内容的操作。
? public Field getField(String name) 返回此Class对象表示的类或接口的指定的 public的Field。
? public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。
获取到Filed后,执行Field上面的方法:
? public Object get(Object obj) 取得指定对象obj上此Field的属性内容,注意get不用传入Class对象
? public void set(Object obj,Object value) 设置指定对象obj上此Field的属性内容
Field name = clazz.getDeclaredField("name"); name.setAccessible(true); name.set(p1,"HanMeimei"); System.out.println(p1);
关于于setAccessible方法:
? Method和Field、Constructor对象都有setAccessible()方法。
? setAccessible启动和禁用访问安全检查的开关。
? 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
? 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被 调用,那么请设置为true。 ? 使得原本无法访问的私有成员也可以访问
? 参数值为false则指示反射的对象应该实施Java语言访问检查。
一句话就是设置为True,私有就不私有了
反射最重要的应用是在动态代理,请移步:https://www.cnblogs.com/wangid3/p/14159821.html
原文:https://www.cnblogs.com/wangid3/p/14159834.html