反射

java 反射机制

  • 反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
  • 原理
    • 手工创建对象,自己来执行类加载器(ClassLoader),调用类模板(Class)的方法获取类的信息,和创建对象
  • 创建对象方式
    1. new
      • 编译时强烈依赖类,硬编码,调用时必须有相关类才能编译通过
    2. 工厂模式
    3. 反序化
    4. 反射机制
      • 编译时不依赖类,软编码,不依赖类(传统依赖类,称为硬编码)
  • 流程
    • 获取类模板类对象
    • 创建需要的对象
    • 或许属性定义对象,再配合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类对象获取
  1. 前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
    • 实例:Class clazz = String.class;
  2. 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
    • 实例:Class clazz = “www.atguigu.com”.getClass();
  3. 前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
    • 实例:Class clazz = Class.forName(“java.lang.String”);
  4. 其他方式
    • 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
  • 方法类对象
    1. Object invoke(Object obj, Object … args) //对象执行,配合对象使用
    2. public void setAccessible(true)//继承自AccessibleObject设置私有方法可见,暴力破解封装性,唯一破解封装性的方法
java.lang.reflect.Field
  • 属性类对象
    1. public Object get(Object obj) //获取属性对象,配合对象使用
    2. public void set(Object obj,Object value) //设置属性
    3. public void setAccessible(true)//继承自AccessibleObject设置属性可见,暴力破解封装性,唯一破解封装性的方法
java.lang.reflect.Constructor
  • 构造器对象

类加载过程

  • 类的加载:将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成
  • 类的连接:将类的二进制数据合并到JRE中
  • 类的初始化:JVM负责对类进行初始化

加载器分类

  • 引导类加载器:加载核心类库
    • 扩展类加载器:加载jar包下的整合框架类库
      • 系统类加载器:加载用户类
  • 双亲调用机制
    • 双亲是:扩展类加载器,引导类加载器
    • 流程
      • 系统加载器首先调用扩展类类加载器加载,
      • 扩展类加载器首先调用引导类加载器加载,
      • 引导类查找是否属于核心类库,有则加载,无则返回
      • 若返回,则扩展类查找是否属于自己的
    • 向上提交,回朔加载,先尝试委派父类加载器加载器加载,被驳回则扫描自己地区域,
    • 目的:安全

posted @ 2018-11-25 10:11  热风轻浮  阅读(87)  评论(0编辑  收藏  举报