关于类加载机制的一些笔记

类加载流程

基本过程:加载——验证——准备——解析——初始化——使用——卸载
加载:
1.获取定义这个类的二进制流,不一定从class文件获取,所以可以自定义类加载器。
2.将二进制流转为JVM方法区的数据结构,载入方法区
3.在方法区中生成Class对象,作为访问这个类信息的外部接口
验证:
1.文件格式验证,校验合法性,比如魔数值”cafebabe”
2.元数据验证,比如类和字段的合法性
3.字节码(指令)验证,即方法有没有恶意代码
准备:
static字段的0值初始化
解析(可能在加载后,初始化前或初始化后,取决于虚拟机)
将常量池的符号引用转为直接引用,即真正的名字,指向地址
初始化:
1.clinit(),static和static{}的赋值,init(),成员变量赋值,构造方法赋值
使用:
卸载:
1.反射对象不被引用
2.没有引用
3.类加载器已经卸载

被动引用不会出发类的初始化,类数组、访问父类static字段、访问其他类的static final 字段(本类在编译完成前就已经获取到常量的值,生成class文件后已和原来提供数据的类无关)

类加载器:双亲委派模型

加载时初始化顺序

先加载父类static变量,再加载子类static变量,再初始化父类普通成员变量和构造方法,再初始化子类成员变量和构造方法。

一个例子

class SingleTon {
    private static SingleTon singleTon = new SingleTon();
    public static int count1;
    public static int count2 = 0;

    private SingleTon() {
        count1++;
        count2++;
    }

    public static SingleTon getInstance() {
        return singleTon;
    }
}

public class Test {
    public static void main(String[] args) {
        SingleTon singleTon = SingleTon.getInstance();
        System.out.println("count1=" + singleTon.count1);
        System.out.println("count2=" + singleTon.count2)为
 0
  } 

}

输出结果为1和0

以下情况不会触发类的初始化

  • 调用父类静态变量
  • 调用final常量
  • 使用 A[] array = new A[10]

关于堆栈等变量的存储位置

堆、方法区都是线程共享,栈、程序计数器线程独立

  • 常量池里面存储的是符号引用(首先要理解什么是符号引用,直接引用),以及final常量的字面值和字符串(字符串也是常量)
  • 成员变量存在堆中(包括作为成员变量的对象的引用,很多人都说所有对象的引用都在栈中,好像不太对,因为栈是线程独立,对应的是各个方法),因为需要new出来才可以使用,依赖于对象实例
  • 局部变量(包括作为形参及其传来的值)的基本数据类型存在栈中(包括变量名及其值)
  • 局部变量的对象的引用存在栈中,实例存在堆中
  • static变量值存在方法区中,引用也在方法区
  • final存在常量池中,字符串也是,如果new String(“xxx”),则在常量池也会存一份,堆中也会,引用指向所在堆
  • static final 值也是常量池中(如果是对象实例在堆,引用在方法区),而常量池在堆中(jdk<=7),所有new出来的都在堆
  • 包装类计算时会自动拆包(装箱),byte,short,char计算后自动转int或更高。
  • Integer(100)实际上是Integer.valueOf(100),-128-127的会使用同一块地址,也就是引用相同。byte的范围刚好是-128-127,因为补码+0,-0对应都是00000000,也就是只有255个补码,规定10000000为-128补码,这就是为什么将byte转为十六进制需要 &0xff

关于内存泄漏部分问题

非静态内部类实例隐式持有外部对象的引用,注意内存泄漏问题
方法内部类(匿名内部类)访问方法的变量必须为final,之所以为final是因为要保持方法原来变量内部类的值的一致性。
强引用
软引用(内存溢出前回收)
弱引用(GC时回收)
虚引用(回收时系统接到通知)

关于Kotlin优雅使用internal

可以使用@JvmName(‘funcn ame’)注解使用不规范方法名,java类将无法调用kotlin
可以直接粗暴使用

fun 'me  thod '(a:Int,b:Int):Int = a + b 

参考文章1
参考文章2

猜你喜欢

转载自blog.csdn.net/sinat_33878878/article/details/78524032
今日推荐