类加载过程代码实例
来源:互联网 发布:java常用api详解 编辑:程序博客网 时间:2024/06/06 02:21
package com.it;/** * Man load 加载 * @author mmry * */public class ManLoad extends User { /*class文件结构 对象结构*/ /*class常量池 utf-8 string int long float double 字母量和变量名字,描述符 class field_ref method-ref interface 其他符号引用 string直接生成string对象*/ /*运行时常量池 加载的时候 符号引用转换为方法区内存的直接引用。转换 方法运行的时候,动态的指向运行时常量池的直接引用。指向 User user=new Man(); user.say(); // #71 class字节码是 User say() public 运行时找动态引用 #60 Man say() public ox0140 _2 全局字符串常量池 哈哈 指向同一个对象。 */ /*--类的加载过程 包括类变量 -----加载 class对象 和验证交叉进行,写入方法区。 -----验证 文件格式 元数据 字节码 符号引用 -----准备 分配内存 ,方法表(自己的,父类的内存地址) -----解析 符号引用转换为直接引用。指向方法区内存 ,静态解析。class常量池里面的符号引用 解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程 -----初始化 clinit方法 -----解析 动态解析。动态链接。方法里面的符号引用*/ /* 方法区类 1 运行时常量池 运行时常量池属于每个类的,指向方法区内存的直接引用。 2 元数据信息,类接口信息,所有方法信息,所有字段信息, (包括继承的吗) 3 class对象引用,classloader引用 4 方法表,包括继承父类的 5 类变量 栈帧 1局部变量表,指向堆引用 2操作数栈 3动态链接,指向运行时常量池。修改指向不同的直接引用。 5 计数器 6方法出口其他信息 堆 分代垃圾回收 */ // 方法引用 字段引用 静态引用 动态引用 String s="哈哈"; //字段引用 String s2="哈哈"; //字段引用 User u; //类字段引用 //静态引用 private void smoke() { System.out.println("我会抽烟"); } //静态引用 private void smoke(String s) { System.out.println("我会抽"+s); } //动态引用 public void say() { System.out.println("我是Man"); } /* 先看方法,在看实际类型 如果是私有方法 构造方法 final方法 super方法,直接执行 其他的就看实际类型*/ public static void main(String[] args) throws InterruptedException { //方法运行时,动态会解析 #57 #60 等符号引用,指向运行时常量池里解析过的地址。 ManLoad man=new ManLoad(); man.start(); // #57 class字节码是 Man start() private 运行时找静态引用 ox0140_3 man.say(); // #60 class字节码是 Man say() public 运行时找动态引用 ox0140 _2 man.smoke(); //#62 class字节码是 Man smoke() private 运行时找静态引用 ox0140 _4 man.smoke("大麻"); // #66 class字节码是 Man smoke(s) private 运行时找静态引用 ox0140 _5 man.eat(); // #75 class字节码是 Man eat() public 运行时找动态引用 User eat() 0x0133_3 System.out.println(man.name); User user=new ManLoad(); user.say(); // #71 class字节码是 User say() public 运行时找动态引用 #60 Man say() public ox0140 _2 System.out.println(user.name); Thread.sleep(100*1000); } private void start() { //方法引用 System.out.println("开始 "); } /*方法区类加载 //方法表 start say main 继承object的方法 Constant pool: 运行时常量池 加载 解析阶段 类加载时,把class常量池复制到运行时常量池, 符号引用转换为内存地址,直接引用 方法运行时,把字节码里面的符号引用。 指向直接引用。动态改变指向直接引用。 * 符号引用 内存直接引用 #1 = Class ox0140 // com/it/Man #3 = Class 0x0133 // com/it/User #56 = Methodref ox0140 _1 // com/it/Man."<init>":()V #57 = Methodref ox0140 _3 // com/it/Man.start:()V #60 = Methodref ox0140 _2 // com/it/Man.say:()V #62 = Methodref ox0140 _4 // com/it/Man.smoke:()V #66 = Methodref ox0140 _5 // com/it/Man.smoke:(Ljava/lang/String;)V #71 = Methodref 0x0133 _2 // com/it/User.say:()V #74 = Fieldref 0x0133 _4 // com/it/ManLoad.name:Ljava/lang/String; #17 = Fieldref ox0140 _6 // com/it/ManLoad.s:Ljava/lang/String; #75 = Methodref 0x0133_3 // com/it/ManLoad.eat:()V 类信息 加载阶段 Man ox0140 User 0x0133 Object 0x0033 字段信息 (是否包括继承的字段?不包括继承的字段name age ) 加载阶段 String s ox0140 _6 String s2 ox0155 User u 方法信息(不包括继承的方法eat()) 加载阶段符号引用:在静态引用如 私有方法,静态方法,构造方法,父类方法,可以确定的,直接转换为直接引用 动态引用。在不能确定方法,都是在运行时看实例类型决定使用哪个方法的直接引用。 say() 字节码指令 ox0140 _2 start() 字节码指令 ox0140_3 smoke() 字节码指令 ox0140 _4 smoke(s) 字节码指令 ox0140 _5 类变量信息 准备阶段和初始化阶段 无 方法表信息 解析阶段 say() ox0140 _2 start() ox0140_3 smoke() ox0140 _4 smoke(s) ox0140 _5 eat() 0x0133_3 继承方法 */ /* 先调用父类构造方法,在初始化自己的成员变量 父类构造方法,会初始化父类的成员变量 * public com.it.ManLoad(); flags: ACC_PUBLIC Code: stack=2, locals=1, args_size=1 0: aload_0 1: invokespecial #13 // Method com/it/User."<init>":()V 先调用父类构造方法 4: aload_0 5: ldc #15 // String 哈哈 7: putfield #17 // Field s:Ljava/lang/String; 10: aload_0 11: ldc #15 // String 哈哈 13: putfield #19 // Field s2:Ljava/lang/String; 16: return LineNumberTable: line 9: 0 line 64: 4 line 65: 10 line 9: 16 LocalVariableTable: Start Length Slot Name Signature 0 17 0 this Lcom/it/ManLoad;*/ }package com.it;public class User { String name="张三"; int age=18; public void say() { System.out.println("我是user"); } public void eat() { System.out.println("我是user eat"); } //方法表 say 继承object的方法 /*Constant pool: #1 = Class 0x0133 // com/it/User #3 = Class 0x0033 // java/lang/Object */ /* * 类 User 0x0133 Object 0x0033 字段信息 String name 0x0133 _4 int age 0x0133 _4 方法信息符号引用:在静态引用如 私有方法,静态方法,构造方法,父类方法,可以确定的,直接转换为直接引用 动态引用。在不能确定方法,都是在运行时看实例类型决定使用哪个方法的直接引用。
say() 字节码指令 0x0133_2 eat() 字节码指令 0x0133_3 方法表 say() 字节码指令 0x0133_2 eat() 字节码指令 0x0133_3 继承方法 */}
0 0