new对象是在干什么,String相关面试题看完这篇以后任凭面试官问

new对象是在干什么,String相关面试题看完这篇以后任凭面试官问
最新回答
傲慢多泪

2023-05-02 03:16:16

new对象是用于在堆内存中动态分配空间并创建一个类的实例,同时完成对象初始化的一系列操作。具体过程如下:

  • 类加载检查JVM首先检查常量池中是否存在该类的全限定名信息。若未加载,则触发类加载过程(加载、链接、初始化),确保类的元数据(如属性、方法、父类等)已存入方法区。

  • 内存分配根据类加载时确定的实例大小,从堆内存中划分一块足够大的空间。分配方式取决于垃圾收集器:

    指针碰撞:堆内存规整时,通过移动指针划分空间(需GC整理内存)。

    空闲列表:堆内存不连续时,维护空闲列表记录可用区域。

  • 默认值初始化JVM将分配的内存中所有字段初始化为默认值(如int为0,boolean为false,引用类型为null)。

  • 对象头设置填充对象头信息,包括:

    对象所属类的元数据指针(指向方法区)。

    哈希码、GC分代年龄、锁状态等运行时数据。

  • 显式初始化执行<clinit>方法(静态代码块)和实例构造器<init>,将字段赋值为代码中定义的初始值(如int i = 4会覆盖默认值0)。

  • 引用关联在栈帧的局部变量表中创建引用变量,并将其指向堆中新创建的对象实例。

new Person()的完整调用过程

以代码为例:

class Person { String name; public void say(String name) { System.out.println("hello " + name); }}public class TestPerson { public static void main(String[] args) { Person person = new Person(); // 关键步骤 person.say("特朗普"); }}
  1. 类加载JVM在方法区加载Person类信息(若未加载),包括属性name和方法say的元数据。

  2. 内存分配与初始化

    在堆中分配内存,初始化name为null。

    设置对象头,指向方法区的Person类信息。

  3. 引用绑定栈帧的局部变量person存储引用地址(如0x11),指向堆中对象实例(地址0x22)。

  4. 方法调用

    执行person.say("特朗普")时,通过引用找到堆对象。

    根据对象头中的类指针,定位方法区的say方法字节码并执行。

从内存模型推导String面试题1. 字符串常量拼接的对象数量String str = "1" + "2" + "3";
  • 答案:仅创建1个对象。
  • 原理:编译期进行字符串折叠优化,直接生成常量"123"存入常量池,运行时无需额外拼接。
2. 常量与变量拼接的比较String s1 = "hello";String s2 = "world";String s3 = "hello world";System.out.println(s3 == "hello" + "world"); // trueSystem.out.println(s3 == s1 + s2); // false
  • s3 == "hello" + "world":编译期折叠为"hello world",与s3指向同一常量池对象。
  • s3 == s1 + s2:变量拼接需在堆中创建新对象(StringBuilder拼接结果),引用不同。
3. new String()的对象数量String str1 = "Trump"; String str2 = new String("Trump");
  • 情况1:常量池已存在"Trump" → 仅在堆创建1个对象,str2引用指向堆。
  • 情况2:常量池无"Trump" → 先在常量池创建1个,再在堆创建1个,共2个对象。
  • 比较结果:System.out.println(str1 == str2); // false(引用地址不同)System.out.println(str1.equals(str2)); // true(值相同)
关键总结
  • new操作涉及类加载、内存分配、初始化、引用绑定等步骤,是对象实例化的核心机制。
  • String面试题需结合常量池优化(如折叠)、运行时拼接行为(变量 vs 常量)及对象引用比较(== vs equals)分析。
  • 理解JVM内存模型(方法区、堆、栈)是推导此类问题的关键基础。