对象创建的过程 拼搏现实的明天。 2024-03-26 14:33 27阅读 0赞 ### 创建对象方法 ### 1、用`new`语句创建对象,这是最常用的创建对象的方式; 2、运用**反射手段**,调用Java.lang.Class或者java.lang.reflect.Constructor类的newInstance()实例方法; 3、调用对象的`clone()`方法; 4、运用**反序列化**手段,调用java.io.ObjectInputStream对象的readObject()方法; -------------------- ### new一个对象的过程(仅限`普通Java对象`非`数组`和`Class对象`等) ### 1. 类加载检查 当Java虚拟机遇到一条字节码`new`指令时,首先将去检查这个指令的`参数`是否能在`常量池`中定位到一个`类的符号引用`,并且检查这个符号引用代表的类是否已被`加载、解析和初始化过`。如果没有,那必须先执行相应的`类加载`过程。 2. 分配内存 在类加载检查通过后,接下来虚拟机将为新生对象分配内存。`对象所需内存的大小在类加载完成后便可完全确定`,为对象分配空间的任务实际上便等同于把一块确定大小的内存块从Java堆中划分出来。 3. 初始化零值 内存分配完成之后,虚拟机必须`将分配到的内存空间都初始化为零值(但不包括对象头)`,如果使用了TLAB的话,这一项工作也可以提前至TLAB分配时顺便进行。这步操作`保证了对象的实例字段在Java代码中可以不赋初始值就直接使用`,使程序能访问到这些字段的数据类型所对应的零值。 4. 设置对象头 接下来,Java虚拟机还要对对象进行必要的设置,例如这个`对象是哪个类的实例`、`如何才能找到类的元数据信息`、`对象的哈希码`(实际上对象的哈希码会延后到真正调用Object::hashCode()方法时才计算)、`对象的GC分代年龄`等信息。这些信息存放在对象的`对象头(Object Header)`之中。根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。 5. 执行`<init>()`方法 在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了。但是从Java程序的视角看来,对象创建才刚刚开始—— `构造函数`,即Class文件中的 `<init>()`方法 还没有执行,`所有的字段都为默认的零值`,对象需要的其他资源和状态信息也还没有按照预定的意图构造好。`new指令之后会接着执行<init>()方法`,按照程序员的意愿对对象进行初始化,这样一个真正可用的对象才算完全被构造出来。 \-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明 -------------------- ### 对象内存分配流程 ### **Further Reading**: [内存分配的两种方式][Link 1] ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNzY0NjYzNg_size_16_color_FFFFFF_t_70_pic_center] -------------------- ### staticObj、instanceObj、localObj这三个变量本身(而不是它们所指向的对象)存放在哪里? ### staticObj随着Test的类型信息存放在`方法区`; instanceObj随着Test的对象实例存放在`Java堆`中; localObject则是存放在foo()`方法栈帧的局部变量表`中; /** * staticObj、instanceObj、localObj存放在哪里? */ public class JHSDB_TestCase { static class Test { static ObjectHolder staticObj = new ObjectHolder(); ObjectHolder instanceObj = new ObjectHolder(); void foo() { ObjectHolder localObj = new ObjectHolder(); System.out.println("done"); // 这里设一个断点 } } private static class ObjectHolder { } public static void main(String[] args) { Test test = new JHSDB_TestCase.Test(); test.foo(); } } \-----------------------------------------------------------------------------读书笔记摘自 书名:深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)作者:周志明 -------------------- ### 什么是不可变对象? 好处是什么? ### 不可变对象指对象一旦被创建,状态就不能再改变,任何修改都会创建一个新的对象; 如 `String`、`Integer`及其它`包装类`; 不可变对象最大的好处是`线程安全`; -------------------- ### 能否创建一个包含可变对象的不可变对象? ### 可以, 比如`final Person[] persons = new Persion[]{}`,persons是不可变对象的引用,但其数组中的Person实例却是可变的。 这种情况下需要特别谨慎,不要共享可变对象的引用。这种情况下,如果数据需要变化时,就返回原对象的一个拷贝。 -------------------- ### 值传递和引用传递的区别的什么?为什么说Java中只有值传递? ### [Java是值传递还是引用传递?][Java] [Link 1]: https://blog.csdn.net/weixin_37646636/article/details/120385876 [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl8zNzY0NjYzNg_size_16_color_FFFFFF_t_70_pic_center]: https://image.dandelioncloud.cn/pgy_files/images/2024/03/26/56612768f0c3429d904cb5acc5a9dfab.png [Java]: https://blog.csdn.net/weixin_37646636/article/details/132134711
还没有评论,来说两句吧...