`

从堆和栈的角度看String对象

阅读更多
String对象问题曾困扰我很长时间,总是不太明白它与基本数据类型之间的区别,看了java内存分配,得到了一点启发,下面从堆和栈的角度看一下String对象在内存中是如何操作的。

首先看一下堆和栈的区别

栈:栈中存放的是基本类型的变量或者引用类型的变量。其中局部变量是通过数组的索引来访问,操作数栈通过栈操作才实现。局部变量有利于内存空间的高效利用, 方法运行完就回收,而对于类成员变量,只要对象还在,即使方法运行结束,成员变量还是存在。

堆:存放通过new关键字新建的对象和数组。声明的对象是在堆内存中初始化,对象的数据存放在堆中,不可以直接访问。引用变量保存了堆中对象的地址,它保存在栈中,用来引用堆中的对象。

栈代表了运行的逻辑,堆代表了运行时的数据。

我们对堆和栈有了基本的理解,现在我们步入正题,String对象。
首先我们从一个例子来看。
String s1 = "hello";
String s2 = new String("hello");
String s3 = "hello";
String s4 = new String("hello");
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s2 == s4);


答案是:false, true, false
首先我们看一下 String s2 = new String("hello"), 和正常的创建对象一样,通过new String("hello") 在堆内存中创建了一个String对象,堆给这个对象分配内存空间,对象的内容是”hello“,记住对象保存在堆中。唯一不同的是JVM为string设置了一个常量池,用new关键字的同时,在常量池中也会产生一个“hello”对象,也就是说 new String("hello")会在堆和字符串常量池中分别创建一个对象。s2就是所谓的引用变量,s2是保存在栈中,它里面的内容是这个对象在堆中的内存地址,正如上面所说对象是不能直接调用的,只能通过引用变量来调用。并且new一次,堆就会给这个对象分配内存空间。对于==操作符,只有当两个引用变量指向同一个对象时才返回true,因此s2 == s4返回false。

对于String s1 = "hello", 它首先会在字符串常量池中寻找是否有‘’hello”,如果存在,就把指向“hello”的引用变量里面的值赋值给新的引用变量,在这个例子中就是把s1里面的内容赋值给s3,他们实际上是指向的同一个对象,因此s1 == s3返回true。如果字符串常量池中不存在“hello”,此时首先在常量池中创建一个对象,然后让当然的引用变量指向这个地址。对于这个例子,s1指向的是常量池里的“hello”,s2指向的是堆中的“hello”,因此s1 == s2返回false。JVM是为了提高效率才设计了这样的操作。如果每次都用new关键字,会造成内存的浪费。

个人的一点体会,如有错误的地方希望大家指出!
4
2
分享到:
评论

相关推荐

    八张图深度理解Java特性

    图 7:堆和栈 图 7 展示了方法和对象在运行时内存中的位置。堆(Heap)是 Java 中的一个内存区域,用于存储对象和数组。栈(Stack)是 Java 中的另一个内存区域,用于存储方法和局部变量。 图 8:Java 虚拟机运行...

    JVM 50 道面试题及答案.docx

    字符串常量池存放在堆中,包括 String 对象执行 intern() 方法后存放的地方和双引号直接引用的字符串。运行时常量池存放在方法区,属于元空间,是类加载后的一些存储区域,大多数是类中 constant_pool 的内容。类...

    java提高性能.pdf

    5. 堆和栈(StackHeap):Java中的内存管理包括栈内存和堆内存。栈是线程私有的,主要存放基本类型变量和对象的引用。堆则是线程共享的,存放对象本身。理解堆和栈的区别对于性能优化至关重要。 6. 垃圾收集...

    JVM内存分配与垃圾回收详解

    Java 堆也是垃圾收集器管理的主要区域,如果从内存回收的角度看,由于现在收集器采用分代收集算法所以可以分为老年代和新生代,再细致有 Eden 空间、from 空间、to 空间,但是无论怎么划分,它都是只是存储对象实例...

    Java上海汉得笔试题+答案解析

    - **选项 B 正确:**从内存回收的角度看,Java 堆中可以细分为新生代和老年代。 **结论:** 正确选项为 C: 所有的对象实例以及数组都要在堆上分配;从内存回收的角度看,Java 堆中可以细分为新生代和老年代。

    asp.net

    - **反设计**:从数据库设计的角度来看,O/R Mapping 的作用是对数据库的反设计,即从对象的角度考虑问题而不是从数据库角度考虑。 #### 6. 类成员的可访问形式 类成员可以有不同的访问修饰符,常见的有: - `...

    用汇编的眼光看C++(之 总结篇)(pdf版本)

    - 从汇编角度看,实例化一个对象时首先会分配足够的内存空间来存储对象的数据成员,随后调用相应的构造函数初始化这些成员。 2. **成员函数调用**: - 成员函数调用通常涉及到了虚函数表和虚函数指针的概念。 - ...

    SUN SCJP 认证笔记

    此外,还需了解基本的内存模型,如堆和栈的区别。 4. **数组与集合框架**:熟练掌握数组的使用,包括一维数组、多维数组及数组操作。同时,理解并能应用Java集合框架中的List、Set、Map接口及其实现类,如ArrayList...

    C++ 参考资料程序

    这份资料包含了C++语言的基础、进阶和实战应用等多个层面的知识点,旨在帮助读者从各个角度深入理解和掌握C++。 1. **C++基础**:C++是一种静态类型的、编译式的、通用的、大小写敏感的、不仅支持过程化编程,也...

    用vb6.0小程序验证我的汉诺塔直接计算移动,不用递归的设想

    - 移动顶部n-1个盘子从A到B,利用C作为辅助柱子,这一步可以通过调用自身来完成,但是我们使用循环和栈来模拟。 - 直接将第n个盘子从A移动到C。 - 将栈B中的n-1个盘子移到C,此时A已经空了,所以直接将B中的盘子...

    性能优化手册100技巧.06版.pdf

    - **避免使用String连接**:在循环中避免使用String连接操作,因为它会创建新的String对象,增加垃圾回收压力。 - **try-catch的合理使用**:在循环体内部避免使用try-catch,因为异常捕获操作是有性能开销的。 - **...

    Unity面试题30题含答案——C#基础.

    - **关系**:从技术角度来看,Mono是.NET的一种开源实现,它遵循了.NET的规范,提供了类似的开发环境和工具链。但是,它更侧重于跨平台性和开放性。 以上内容涵盖了Unity面试题中提到的C#基础知识点,通过对这些...

    day17_线程创建、线程同步、线程状态.pdf

    进程:有独立的内存空间,进程中的数据存放空间(堆空间和栈空间)是独立的,至少有一个线程。 线程:堆空间是共享的,栈空间是独立的,线程消耗的资源比进程小的多。 3. 多线程的随机性 由于一个进程中的多个...

    javascript内存分配原理实例分析

    从内存分析的角度看,原始值和引用值的这种分配方式,是为了兼顾效率和灵活性。栈内存的快速存取适合存储简单的数据,而堆内存则能处理更复杂的对象结构,允许动态分配和回收内存,由垃圾回收器自动管理。 然而,这...

    ACM-ACM竞赛常用模板-C++.zip

    C++作为一门强大的面向对象编程语言,因其高效、灵活的特点,常被选为参赛选手的主要编程工具。本资料集合了ACM竞赛中的常用C++模板,旨在帮助参赛者快速理解和应用关键算法,提高解题效率。 一、基础模板 1. 输入...

    新手学习C++入门资料

    标准C++的iostream类库中包括了可以支持宽字符的类和对象。用wout替代cout即可。 #include iostream.h int main() { wchar_t wc; wc='b'; wout; wc='y'; wout; wc='e'; wout; return 0; } 说明一下...

    js中null与空字符串""的区别讲解

    2. 在JavaScript引擎中,变量和引用变量通常存储在栈(stack)上,而对象则是存储在堆(heap)上的。当引用变量指向null时,意味着它实际上并没有指向堆上的任何对象。而当引用变量指向一个空字符串""时,它指向的是...

    java代码-3

    理解JVM的工作原理,包括垃圾收集(Garbage Collection)和内存区域划分(堆、栈、方法区等),对于优化性能和避免内存泄漏至关重要。 10. **标准库与API**:Java提供了一个庞大的标准库,包括各种实用工具类、网络...

Global site tag (gtag.js) - Google Analytics