String类的常见问题

1.判定定义为String类型的两个对象是否相等(1)

public class StringDemo01 {public static void main(String[] args) {String string01 = "zrt";String string02 = "zrt";System.out.println(string01 == string02);     //trueSystem.out.println(string01.equals(string02));    //true}
}

分析:

  1. 在Java中“==”这个符号比较运算符,可以用来比较基本数据类型引用数据类型是否相等

    • 基本数据类型:比较的是值是否相等

    • 引用数据类型:比较的是两个对象的内存地址是否相等

    • 注意的是,String类型不属于八种基本数据类型,换句话说,String对象属于引用数据类型。将"zrt"同时赋值给了两个String类型的对象,而且两个String类的引用都是指向同一个地址,故第一个语句为“true”。

  2. Object类提供的equals()方法,在String类(继承了Object类)中重写了equals()方法,通过JDK文档可知,此方法的解释为“将此字符串与指定的对象比较。当且仅当该参数不为null,并且是与此对象表示相同字符序列String对象时,结果才为true。”因为string01和strin02的值都为"zrt",具有相同字符序列,故第二个语句为“true”。

  3. 上述例子的内存图如下:

此过程大致如下:

  • 运行先编译,将当前类StringDemo01.class文件加载进入内存的方法区。
  • main方法压入栈内存。
  • 常量池创建一个“zrt”对象,产生一个内存地址。
  • 然后把“zrt”内存地址赋值给main方法里的成员变量string01,这个时候string01根据内存地址,指向了常量池中的“zrt”。
  • 常量池有个特点,发现字符串对象“zrt”已经存在,就不在创建重复的对象。
  • 运行到代码 String string02 =”zrt”, 由于常量池存在“zrt”,直接把“zrt”内存地址赋值给了string02。
  • 所以,string01和string02 都指向了内存中同一个地址,所以两者是完全相同的。

2.内存中创建对象的个数

public class StringDemo02 {public static void main(String[] args) {String string01 = "zrt";}
}

上述例子在内存中创建了多少个对象呢?

答案便是:两个,一个堆内存,一个在常量池,而且堆内存对象是常量池对象的一个拷贝副本

分析:我们都知道new这个关键词,new出来的对象都是存储在堆内存。“zrt”属于字符串,字符串属于常量,所以应该在常量池中创建,所以第一个创建的对象就是在常量池中的”zrt“。那为什么说堆内存对象是常量池的一个拷贝副本呢?从JDK1.6的文档中,可以看到构造方法String(String original) 的注释:”初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列“。也就是说,新创建的字符串就是该参数字符串的副本。换句话说,便是堆内存对象是常量池对象的一个拷贝副本

上述例子的内存图如下:


3.判定定义为String类型的两个对象是否相等(2)

public class StringDemo03 {public static void main(String[] args) {String string01 = new String("zrt");String string02 = "zrt";System.out.println(string01 == string02);     //falseSystem.out.println(string01.equals(string02));   //true}
}

分析:”==“比较的string01对象和string02对象的内存地址,由于string01指向的是堆内存的地址,string02看到“zrt”已经在常量池存在,就直接指向了常量池的内存地址,所以,第一个语句的输出结果false。第二个equals()放法比较,比较是两个字符串序列是否相等,由于都是“zrt”,故第二个语句的输出结果为true。

上述例子的内存图如下:


4.判定定义为String类型的两个对象是否相等(3)

public class StringDemo04 {public static void main(String[] args) {String string01 = "z" + "r" + "t";String string02 = "zrt";System.out.println(string01 == string02);     //trueSystem.out.println(string01.equals(string02));    //true}
}

分析:“z”,”r”,”t”本来就是三个字符串常量,经过”+“符号进行拼接之后变成了字符串“zrt”,而“zrt”本身就是字符串常量(Java中有常量优化机制),所以会在常量池创建一个“zrt”的字符串常量对象。因此,在进行到string02=”zrt”的时候,因为常量池存在“zrt”,所以不会再创建“zrt”字符串对象。故无论是比较内存地址还是比较字符串序列,都相等,所以两个语句的输出结果都是true。


5.判定定义为String类型的两个对象是否相等(4)

public class StringDemo05 { public static void main(String[] args) {String string01 = "zrt";String string02 = "zrt";String string03 = string01 + "t";System.out.println(string02 == string03);       //falseSystem.out.println(string02.equals(string03));   //true}
}

其中,第二个语句的输出结果为true,此处不再赘述。主要是为什么第一个语句的输出结果为什么是false呢?首先我们可以在JDK API1.6的文档中看到这样一句话:

Java 语言提供对字符串串联符号("+")以及将其他对象转换为字符串的特殊支持。字符串串联是通过 StringBuilder(或 StringBuffer)类及其 append 方法实现的。字符串转换是通过 toString 方法实现的,该方法由 Object 类定义,并可被 Java 中的所有类继承。

分析:由上我们可知:任何数据和字符串进行加号(+)运算,最终得到是一个拼接而成新的字符串。上面注释说明了这个拼接的原理是由StringBuilder或者StringBuffer类和里面的append方法实现拼接,然后调用toString()把拼接的对象转换成字符串对象,最后把得到字符串对象的内存地址赋值给变量。

上述例子的内存图如下:

过程大致如下:

  • 常量池创建“zr”对象,并将其内存地址值赋值给string01,所以string01指向了“zr”。
  • 常量池创建“zrt”对象,并将其内存地址值赋值给string02,所以string02指向了“zrt”。
  • 由于语句用的是“+”进行拼接string01和字符串对象“t”,所以是使用StringBuffer类的append()方法,得到了StringBuffel对象“zrt”(注意:现在还不是String对象),用0x01表示内存地址。
  • 调用Object类的toString()方法,将StringBuffer对象转换成String对象,用0x01表示内存地址。
  • 将String对象的内存地址(0x02)赋值给string03。所以进行“==”判断的输出结果为false,因为内存地址不同。

6.总结

这篇文章,是我在学习String类的时候遇到一个小疑惑,做成笔记加深印象,重点就是理解JDK API一些注解和原理、内存图。通过画内存图也可以帮助我们理解其中的原理。


String类的常见问题相关推荐

  1. java的知识点15——String基础、String类和常量池、String类常用的方法、字符串相等的判断、组合模式

    String基础 1. String类又称作不可变字符序列. 2. String位于java.lang包中,Java程序默认导入java.lang包下的所有类. 3. Java字符串就是Unicode ...

  2. C++ 笔记(22)— STL string 类(字符串赋值、访问、拼接、查找、翻转、大小写转换)

    1. 实例化和赋值 STL string #include <string> #include <iostream>int main () {using namespace s ...

  3. java string改变的影响_为什么Java的string类要设成immutable(不可变的)

    最流行的Java面试题之一就是:什么是不可变对象(immutable object),不可变对象有什么好处,在什么情况下应该用,或者更具体一些,Java的String类为什么要设成immutable类 ...

  4. C++——String类超详细介绍

    (欢迎及时指正错误!谢谢) STL的含义:标准模板库 STL的内容: 容器:数据的仓库 算法:与数据结构相关的算法.通用的算法(和数据结构无关) 注:熟悉常用的算法 sort  reverse 迭代器 ...

  5. 标准C++中的string类的用法总结

    相信使用过MFC编程的朋友对CString这个类的印象应该非常深刻吧?的确,MFC中的CString类使用起来真的非常的方便好用.但是如果离开了MFC框架,还有没有这样使用起来非常方便的类呢?答案是肯 ...

  6. c++ string replace_JAVA应用程序开发之String类常用API

    [本文详细介绍了JAVA应用开发中的String类常用API,欢迎读者朋友们阅读.转发和收藏!] 1 基本概念 API ( Application Interface 应用程序接口)是类中提供的接口, ...

  7. javascript:为string类添加三个成员,实现去左,右,及所有空格

    <script language="JavaScript">    //此处为string类添加三个成员    String.prototype.Trim = func ...

  8. 字符串(string类)

    [1]String类基本函数如何实现? 示例代码如下: 1 #include<iostream> 2 #include<assert.h> 3 #include<stri ...

  9. 交换变量和String类初始化:JAVA入门基础

    本文主要介绍了变量交换.String类初始化.字符串的基本操作.变量交换详解介绍了两个变量是如何交换的,通过例子理解这个用法. 一.交换变量 1.什么是交换变量 例如用户输入a.b的值分别3,9的整数 ...

最新文章

  1. 芯片初创公司一亿融资可以烧多久
  2. VMware15克隆虚拟机Centos
  3. java中打开的线程怎么关闭_[求助] 用线程怎么关闭运行中的窗口
  4. Python类的部分
  5. js复制数据IE,FF..浏览器兼容
  6. VTK:PolyData之CellLocatorVisualization
  7. PHP与SQL注入攻击
  8. python max取下标_Python 变量类型总结
  9. 怎么把打开方式改回计算机程序,电脑打开方式改变了,怎么还原
  10. redis五种数据类型的使用场景
  11. 【苹果相册推送】excerantione system.out.printlni 家哦,==电子电子邮件
  12. 带你快速入门AXI4总线--AXI4-Stream篇(1)----AXI4-Stream总线
  13. C#测试调用PaddleSharp模块识别图片文字
  14. 沉病孩子留遗嘱 父疏申请接济劫持红十字员农
  15. 【附源码】计算机毕业设计SSM企业合同管理系统
  16. 计算机教学音乐,计算机音乐的教学和应用研究
  17. 如何加载3D模型(odj文件和mtl文件)
  18. iNFTnews | 呵护“雪山精灵”,42VERSE“数字生态保护”公益项目即将盛启
  19. 紧随小米2:LG Optimus G也用高通四核APQ8064
  20. python对象的生命周期_python对象的生命周期

热门文章

  1. 微信公众号聊天室 私聊功能演示
  2. 云呐|什么是容灾备份一体机?
  3. Django2.0——Form组件简单总结
  4. Dual Self-Attention Network (DSANet)
  5. linux tail 命令详解,Linux下如何使用tail命令指南
  6. 面试经历(签约华为,违约华为,签约移动)
  7. 公共关系礼仪实务章节测试题——公共关系的类型(三)
  8. 使用Java模拟Web端的POST或GET请求,实现自动化操作:加密狗烧制技术详解
  9. 2022年塔式起重机司机(建筑特殊工种)考题及在线模拟考试
  10. 运动员svg图标素材推荐 精品 小众