java反射机制及类加载过程

  1. 在讲java反射机制之前,先了解下静态语言和动态语言.
  • 动态语言:
    是一类在运行时可以改变其结构的语言.在运行时代码可以根据某些条件改变自身结构.例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其结构上的改变.
    比如动态语言有: Python、PHP、C#、JavaScript、Object-C
  • 静态语言:
    和动态语言相对,在运行时结构不可变的语言.
    比如静态语言有:Java、C、C++.
  • 虽然Java不是动态语言,但是Java可以被称之为“准动态语言”,原因就在于Java的反射机制可以使得开发者获得类似动态语言的特性.
  1. 反射
    反射(Reflection)是Java被视为动态语言的关键,反射机制允许程序在执行期间借助于Reflection API获取类的所有内部信息,并能直接操作对象的所有内部属性及方法.
    加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象,也就是.class二进制文件),这个对象包含了完整的类的结构信息.我们可以通过这个对象看到类的结构.这个对象就像一面镜子,透过这个镜子看到类的结构,所以形象的称之为:反射.
    正常方式:
    引入需要的“包类”名称(import) -> 通过new实例化 -> 取得实例化对象
    反射方式:
    实例化对象 -> getClass()方法 -> 得到完整的“包类”名称.
    注: getClass()方法这只是得到Class对象的其中一种方式.

  2. Java反射的优缺点
    优点:
    可以实现动态创建对象和编译,体现出很大的灵活性
    缺点:
    对性能有影响.使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求.这类操作总是慢于直接执行相同的操作.

  3. 获取Class对象的几种方式

  • 通过类的class属性获取
    Class c = Person.class;
    
  • 通过类的实例的getClass()方法获取
    Class c = person.getClass();
    
  • 通过Class类的静态方法forName()获取
    Class c = Class.forName("com.kenai.Person");
    
    注: 全类名=包名+类名
  • 内置基本数据类型可以通过类名.TYPE获取
    Class c = Integer.TYPE;
    
  • 利用ClassLoader类加载器获取
  1. 通过Class对象可以获取什么信息?
    可以获取该类的参数(包括private)、方法、构造函数、父类信息等等

  2. 哪些类型可以有Class对象

  • 类: 外部类、成员内部类、静态内部类、局部内部类、匿名内部类
  • 接口
  • 数组
  • 枚举
  • 注解@interface
  • 基本数据类型
  • void
  1. class对象是在什么时候生成的呢?
    在类加载的时候生成.
    这就涉及到类的加载过程:
  • 加载
    将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时数据结构,然后生成一个代表该类的java.lang.class对象.
  • 链接(将类的二进制数据合并到JRE中).分为以下三步:
    • 验证: 加载的类信息是否符合JVM规范
    • 准备: 为类的静态变量分配内存,并将其初始化为默认值
    • 解析: 将常量池中的符号引用(常量名)替换成直接引用(地址)
  • 初始化
    为静态变量和静态代码执行初始化工作,将静态变量值设置为真正的初始值.
  • 注: 类加载的时候只为静态变量和静态代码块执行初始化工作,非静态初始化块在每个对象生成时都会被执行一次
  1. 什么时候会发生类的初始化呢?(发生类的主动引用)
  • 当虚拟机启动时,初始化main方法所在类
  • new一个类
  • 调用类的静态成员(除了final常量)和静态方法
  • 使用java.lang.reflect包的方法对类进行反射调用
  • 当初始化一个类,如果其父类没有被初始化,则会先初始化其父类.
  1. 什么时候不会发生类的初始化?(类的被动引用)
  • 当访问一个静态域,只有真正声明这个域的类才会被初始化.
    比如当通过子类引用父类的静态变量,会导致父类的初始化,而不是导致子类的初始化.
  • 通过数组定义类引用,不会触发此类的初始化.
  • 引用final常量不会触发此类的初始化(常量在链接阶段就存入diao)
  1. 反射中invoke的使用
public class User{
	private String name;
	private Int age;
	public void setName(String name){
		this.name = name
	}
	public String getName(){
		return this.name;
	}
}

public class test{
	public static void main(String[] args){
		// 获取User的Class对象,参数为类的全路径
		Class c = Class.forName("...User")
		// 获取User实例对象
		User user = (User)c.new Instance();
		// 通过反射获取一个方法
		Method setName = c.getDeclaredMethod("setName", String.Class);
		setName.invoke(user, "zlj");
		System.out.println(user.getName);
		// 通过反射操作属性
		Field name = c.getDeclaredField("name");
		// 想要获取私有的属性/方法,必须通过setAccessible()方法关闭程序的安全检测
		name.setAccessible(true);
		// 为属性name的set方法赋值
		name.set(user, "wangwu");
		System.out.println(user.getName);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值