java 反射机制
- 反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
- 原理
- 手工创建对象,自己来执行类加载器(ClassLoader),调用类模板(Class)的方法获取类的信息,和创建对象
- 创建对象方式
- new
- 编译时强烈依赖类,硬编码,调用时必须有相关类才能编译通过
- 工厂模式
- 反序化
- 反射机制
- 编译时不依赖类,软编码,不依赖类(传统依赖类,称为硬编码)
- 流程
- 获取类模板类对象
- 创建需要的对象
- 或许属性定义对象,再配合this对象完成对象属性的访问
反射机制提供的功能
- 在运行时判断任意一个对象所属的类
- 在运行时构造任意一个类的对象
- 在运行时判断任意一个类所具有的成员变量和方法
- 在运行时调用任意一个对象的成员变量和方法
- 生成动态代理
反射相关的主要API:
java.lang.Class
- Class本身也是一个类
- Class 对象只能由系统建立对象
- 一个类在 JVM 中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个.class文件
- 每个类的实例都会记得自己是由哪个 Class 实例所生成
- 通过Class可以完整地得到一个类中的完整结构
方法:
方法名 |
功能说明 |
static Class forName(String name) |
返回指定类名 name 的 Class 对象 |
Object newInstance() |
调用缺省构造函数,返回该Class对象的一个实例 |
String getName() |
返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 |
Class [] getInterfaces() |
获取当前Class对象的接口 |
ClassLoader getClassLoader() |
返回该类的类加载器 |
Class getSuperclass() |
返回表示此Class所表示的实体的超类的Class |
Constructor[] getConstructors() |
返回一个包含某些Constructor对象的数组 |
Field[] getDeclaredFields() |
返回Field对象的一个数组 |
Method getMethod(String name,Class … paramTypes) |
返回一个Method对象,此对象的形参类型为paramType |
String str = "test4.Person"; //自定义类
Class clazz = Class.forName(str); //获取类模板对象
Object obj = clazz.newInstance(); //获取对象
Field field = clazz.getField("name"); //获取属性类对象,用来操作属性
field.set(obj, "Peter"); //设置属性
Object obj2 = field.get(obj); //获取属性
System.out.println(obj2); //打印拿到的属性
Class类对象获取
- 前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
- 实例:Class clazz = String.class;
- 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
- 实例:Class clazz = “www.atguigu.com”.getClass();
- 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
- 实例:Class clazz = Class.forName(“java.lang.String”);
- 其他方式
- ClassLoader cl = this.getClass().getClassLoader();//类加载器
- Class clazz4 = cl.loadClass(“类的全类名”); //类加载器加载类模板得类模板
ClasaLoader类,类加载器类
- 加载类
- 获取资源(因为类加载器的特殊性,使其有很高的权限可以访问jar和src各处,区别文件系统和包名)
//例,类加载器获取jdk,jar,src任意目录下的资源
public class Main4 {
public static void main(String[] args) {
//由类的class属性生成加载器
ClassLoader classLoader = Main4.class.getClassLoader();
//通过类加载器的getResourseAsSteam方法建立流
InputStream asStream = classLoader.getResourceAsStream("qw");
Properties properties = new Properties();
try {
properties.load(asStream);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Enumeration propertyNames = properties.propertyNames();
while (propertyNames.hasMoreElements()) {
Object object = (Object) propertyNames.nextElement();
Object object2 = properties.get(object);
System.out.println(object + " : " + object2);
}
}
}
java.lang.reflect.Method
- 方法类对象
- Object invoke(Object obj, Object … args) //对象执行,配合对象使用
- public void setAccessible(true)//继承自AccessibleObject设置私有方法可见,暴力破解封装性,唯一破解封装性的方法
java.lang.reflect.Field
- 属性类对象
- public Object get(Object obj) //获取属性对象,配合对象使用
- public void set(Object obj,Object value) //设置属性
- public void setAccessible(true)//继承自AccessibleObject设置属性可见,暴力破解封装性,唯一破解封装性的方法
java.lang.reflect.Constructor
类加载过程
- 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
- 类的连接:将类的二进制数据合并到JRE中
- 类的初始化:JVM负责对类进行初始化
加载器分类
- 引导类加载器:加载核心类库
- 双亲调用机制
- 双亲是:扩展类加载器,引导类加载器
- 流程
- 系统加载器首先调用扩展类类加载器加载,
- 扩展类加载器首先调用引导类加载器加载,
- 引导类查找是否属于核心类库,有则加载,无则返回
- 若返回,则扩展类查找是否属于自己的
- 向上提交,回朔加载,先尝试委派父类加载器加载器加载,被驳回则扫描自己地区域,
- 目的:安全