目录
何为反射?
反射(Reflection),是指Java程序具有 在运行期 分析类以及修改其本身状态或行为的能力
。
通俗点说 就是 通过反射我们可以 动态地 获取一个类的所有属性和方法,还可以操作这些方法和属性。
实例的创建
一般我们创建一个对象实例 Person zhang = new Person();
虽然是简简单单一句,但JVM内部的实现过程是复杂的:
- 将硬盘上指定位置的Person.class文件加载进内存
- 执行main方法时,在栈内存中开辟了main方法的空间(压栈-进栈),然后在main方法的栈区分配了一个变量zhang。
- 执行new,在堆内存中开辟一个 实体类的 空间,分配了一个内存首地址值
- 调用该实体类对应的构造函数,进行初始化(如果没有构造函数,Java会补上一个默认构造函数)。
- 将实体类的 首地址赋值给zhang,变量zhang就引用了该实体。(指向了该对象)
其中上图步骤1 Classloader(类加载器) 将class文件加载到内存中具体分为3个阶段:加载、连接、初始化
而又在 加载阶段,类加载器 会 将类对应的.class文件中的二进制字节流读入到内存中,将这个字节流转化为方法区的运行时数据结构,然后在堆区创建一个**java.lang.Class 对象**(类相关的信息),作为对方法区中这些数据的访问入口
详情可看笔者之前写过的2篇文章:
谈谈JAVA中对象和类、this、super和static关键字
然后再通过 类的实例 来执操作 类的方法和属性 ,比如 zhang.eat(), zhang.getHeight()
等等
如果我们使用反射的话,我们需要拿到该类Person的Class对象,再通过Class对象来操作 类的方法和属性或者创建类的实例
Class personClass = Person.class;//这边只是举一个例子,获取class对象的多种方式,本文后面再慢慢道来 Object person = personClass.newInstance();
我们可以发现 通过new创建类的实例和反射创建类的实例,都绕不开.class文件 和 Class类的。
.class文件
首先我们得先了解一下 什么是.class文件
举个简单的例子,创建一个Person类:
public class Person { /** * 状态 or 属性 */ String name;//姓名 String sex;//性别 int height;//身高 int weight;//体重 /** * 行为 */ public void sleep(){ System.out.println(this.name+"--"+ "睡觉"); } public void eat(){ System.out.println("吃饭"); } public void Dance(){ System.out.println("跳舞"); } }
我们执行javac命令,编译生成Person.class文件
然后我们通过vim 16进制 打开它
#打开file文件 vim Person.class #在命令模式下输入.. 以16进制显示 :%!xxd #在命令模式下输入.. 切换回默认显示 :%!xxd -r
不同的操作系统,不同的 CPU 具有不同的指令集,JAVA能做到平台无关性,依靠的就是 Java 虚拟机。
.java源码是给人类读的,而 .class字节码是给JVM虚拟机读的 ,计算机只能识别 0 和 1组成的二进制文件,所以虚拟机就是我们编写的代码和计算机之间的桥梁。
虚拟机将我们编写的 .java 源程序文件编译为 字节码 格式的 .class 文件,字节码是各种虚拟机与所有平台统一使用的程序存储格式,class文件主要用于解决平台无关性的中间文件
Person.class文件 包含Person类的所有信息
Class类
我们来看下jdk的官方api文档对其的定义:
Class类的类表示正在运行的Java应用程序中的类和接口。 枚举是一种类,一个注释