11 java创建对象的过程(要背下来)

1.类加载检查:
(检查是否被加载过,没被加载过要进行类加载)
首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。
2.分配内存:
(把一块内存从堆里分配出来,尺寸在类加载完就可确定,
gc收集器serial、parnew->标记-整理算法->堆内存规整->指针碰撞分配法->用过的在一边,边上放个指针,分配内存时指针挪一下,
gc收集器cms->标记-清除算法->堆内存不规整->空闲列表法->维护一个可用区域列表,分粗体配内存时找一块而足够大的地方,然后更新列表)
内存分配并发
CAS+失败重试
TLAB: 为每一个线程在Eden区分配一块儿内存,分配内存时先在这分配,不够了再cas+重试
3.初始化零值:
将分配到的内存空间都初始化为零值(不包括对象头),保证了对象不赋初值就可以直接用
4.设置对象头
对象是哪个类(类型指针)、如何找这个类的元数据信息、对象的哈希码、对象的 GC 分代年龄等信息存放在对象头中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。
5.执行 init 方法
初始化对象

对象的内存布局
1.对象头 2.实例数据部分 3.对其填充部分:对象起始地址必须是8的整数倍

对象的访问定位
11 java创建对象的过程(要背下来)_第1张图片
好处:对象换地址时只需要改句柄里的实例地址,不需要改栈里的引用
image.png
好处:找对象快

string类和常量池
String str1 = "abcd"; 带双引号全是在常量池中创建
String str2 = new String("abcd"); 先在常量池里创建了一个,又在堆中创建了一个
string str3 = str2.intern();native方法,如果常量池里有它,返回它。没有它,就创建它然后返回它。

String str1 = "str"; //常量池 str
String str2 = "ing"; //常量池 str
          
String str3 = "str" + "ing";//常量池中的对象 string
String str4 = str1 + str2; //在堆上创建的新的对象    string  
String str5 = "string";//常量池中的对象 已有了
System.out.println(str3 == str4);//false 一个堆 一个常量池
System.out.println(str3 == str5);//true 同一个
System.out.println(str4 == str5);//false 一个堆 一个常量池

Byte,Short,Integer,Long,Character,Boolean实现了常量池技术,默认创建了数值[-128,127]的相应类型的缓存数据,但是超出此范围仍然会去创建新的对象。
Integer i1=40;使用常量池中的对象。
Integer i1 = new Integer(40);创建新的对象,两个40可能不相等
Float,Double 并没有实现常量池技术

        Integer i1 = 33;
        Integer i2 = 33;
        System.out.println(i1 == i2);// 输出true
        Integer i11 = 333;
        Integer i22 = 333;
        System.out.println(i11 == i22);// 输出false
        Double i3 = 1.2;
        Double i4 = 1.2;
        System.out.println(i3 == i4);// 输出false
  Integer i1 = 40;
  Integer i2 = 40; 
  Integer i3 = 0;
  Integer i4 = new Integer(40);
  Integer i5 = new Integer(40);
  Integer i6 = new Integer(0);
i1=i2   true
i1=i2+i3   true
i1=i4   false
i4=i5   false
i4=i5+i6   true
40=i5+i6   true
//两个integer相“+”,加号只适用于基本类型,会拆箱,拆箱了就变成数值对比

你可能感兴趣的:(java)