话题是由如下的事情引出的:
- public class StringTest {
- public static void main(String[] args) {
- String str1 = new String("abc");
- String str2 = "abc";
- if (str1 == str2) {
- System.out.println("str1 == str2");
- } else {
- System.out.println("str1 != str2");
- }
- String str3 = "abc";
- if (str2 == str3) {
- System.out.println("str2 == str3");
- } else {
- System.out.println("str2 != str3");
- }
- str1 = str1.intern();
- if (str1 == str2) {
- System.out.println("str1 == str2");
- } else {
- System.out.println("str1 != str2");
- }
- String str4 = new String("abc");
- str4 = str4.intern();
- if (str1 == str4) {
- System.out.println("str1 == str4");
- } else {
- System.out.println("str1 != str4");
- }
- }
- }
这段程序的输出是什么?
答案:
- str1 != str2
- str2 == str3
- str1 == str2
- str1 == str4
先看看String类型的对象的产生方法:
String有一个所谓的String constant pool ,是一个特殊的一个空间(注意这个是在栈上)保存String常量。String str = “abc”是先定义一个名为str的对String类的对象引用变量:String str;再先用equals方法(String类覆盖了equals方法)判断这个特殊空间(String constant pool )是否有abc,有则将原来在栈中指向abc的引用赋值给str,否则就在这个特殊空间(String constant pool )上开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o 的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。最后将str指向对象o的地址。
String str2 = new String("abc")则是在普通堆上创建abc对象。所以str和str2是指向不同的对象,它们是不同的。那么这样话程序的3--18行就好理解了。
而String有个intern()方法,这个方法是个本地方法,它相当于告诉JVM,我这个abc对象是放在特殊空间(String pool)上的。所以20--27打印的结果是相等的。
注意的是:String是final类,一旦创建就无法改变,所以用intern()方法是重新在String pool中创建了一个新的对象。所以28--37打印的结果是相等的。
最后提一句:当比较包装类里面的数值是否相等时,用equals()方法;当测试两个包装类的引用是否指向同一个对象时,用==。
那么就顺带说一说堆和栈。
堆是动态地分配内存大小,生存期也不必事先告诉编译器,垃圾自动回收负责回收,但由于在运行时动态分配内存,存取速度较慢。在堆上分配空间是通过new等指令建立的,类实例化的对象就是从堆上去分配空间的。
栈中主要存放一些基本类型的变量(int、short、 long、byte、float、double、boolean、char)和对象句柄,存取速度比堆要快。注意包装类数据,如Integer, String, Double等将相应的基本数据类型包装起来的类。这些不是在栈上的。
另外,栈数据可以共享。
例如:
int a = 5;
int b = 5;
它的工作方式是这样的。
JVM处理int a = 5,首先在栈上创建一个变量为a的引用,然后去查找栈上是否还有5这个值。如果没有找到,那么就将5存放进来,然后将a指向5。接着处理int b = 5,在创建完b的引用后,因为在栈中已有5这个值,便将b直接指向5。
于是,就出现了a与b同时指向5的内存地址的情况。
下午和一个线上的朋友聊起这些事情,他给了建议去看JVM的相关书籍,还介绍了用javap来看,方法都很好的。
分享到:
相关推荐
11.java基础拾遗--匿名内部类语法详解.mp4
09.java基础拾遗--类的加载和对象的构造过程.mp4
10.java基础拾遗--匿名内部类的应用--实现scala中的集合map方法.mp4
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
Java开发中的三大框架,即Struts、Hibernate和Spring,各自解决了传统Java Web应用程序中的不同问题,提升了开发效率和代码质量。下面将详细讲解这三个框架的技术起源及其核心功能。 首先,Struts框架诞生于解决JSP...
Java开发中的三大框架——Struts、Hibernate和Spring,都是为了解决传统Java Web应用程序中存在的一系列问题而诞生的。...随着技术的不断发展,Java开发者需要持续学习和掌握这些框架,以适应日新月异的开发需求。
### Spring MVC 学习知识点概览 #### 一、Spring MVC 概述 Spring MVC 是 Spring Framework 的一个重要模块,主要用于简化 Web 应用程序的开发。它提供了清晰的模型视图控制器架构,使得开发者能够更好地组织代码...
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。
《路边拾遗》是一本由两位非职业摄影师创作的摄影画册,书中不仅收录了他们拍摄的精美照片,更重要的是传达了作者对摄影艺术的理解与感悟。通过这本画册,我们可以深刻理解摄影不仅仅是一种技术活动,更是一种心灵的...
Java语言拾遗 │ │ └─util 工具类 │ └─mq 消息队列 │ └─kafka └─resources 消息队列源码会作专题研究 关于消息队列使用参考另一个库:https://github.com/GitJavaProgramming/springboot_mybatis 参考...
java回顾、知识整理、拾遗、面试_java-review
Java知识拾遗:三大框架的技术起源 本篇文章主要讲述了Java开发中三大框架的技术起源,即Struts、Hibernate和Spring框架。这些框架是我们Java开发中的常用的框架,它们分别针对不同的应用场景给出最合适的解决方案...
读书笔记:算法 并发 函数式编程 java语言拾遗 手写设计模式
NULL 博文链接:https://langyu.iteye.com/blog/1167581
在"Java基础"部分,你可以学习到如何声明和初始化变量,如整型(int)、浮点型(float)、字符型(char)和布尔型(boolean)等基本数据类型。此外,还有运算符的使用规则,例如算术运算符(+, -, *, /, %)、关系运算符(==, !...
### 数学拾遗—All the Mathematics You Missed #### 核心知识点概览 《数学拾遗—All the Mathematics You Missed》这本书旨在为初入研究生阶段的学生提供一个全面而深入的数学背景介绍。该书涵盖了众多核心数学...