Java基础提升篇:理解String 及 String.intern() 在实际中的应用

String的深入解析

  • 首先String不属于8种基本数据类型,String是一个对象。     因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。
  • new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;
  • -
1String str=”kvill”; 
2    String str=new String (“kvill”);

的区别:

  在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。 常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量

例1:

1String s0=”kvill”; 
2String s1=”kvill”; 
3String s2=”kv” + “ill”; 
4System.out.println( s0==s1 ); 
5System.out.println( s0==s2 );

结果为: true true

  首先,我们要知道Java会确保一个字符串常量只有一个拷贝。   因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”kvill”的一个引用。   所以我们得出s0==s1==s2;

  用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

例2:

1String s0=”kvill”; 
2String s1=new String(”kvill”); 
3String s2=”kv” + new String(“ill”); 
4System.out.println( s0==s1 ); 
5System.out.println( s0==s2 ); 
6System.out.println( s1==s2 );

结果为: false false false

例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半部分new String(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。

String.intern():

  再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了

 1String s0= “kvill”; 
 2String s1=new String(”kvill”); 
 3String s2=new String(“kvill”); 
 4System.out.println( s0==s1 ); 
 5System.out.println( “**********” ); 
 6s1.intern(); 
 7s2=s2.intern(); //把常量池中“kvill”的引用赋给s2 
 8System.out.println( s0==s1); 
 9System.out.println( s0==s1.intern() ); 
10System.out.println( s0==s2 );

结果为: false ** false //虽然执行了s1.intern(),但它的返回值没有赋给s1 true //说明s1.intern()返回的是常量池中”kvill”的引用 true

最后我再破除一个错误的理解:

  有人说,“使用String.intern()方法则可以将一个String类的保存到一个全局String表中,如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串,则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话,他的最后一句话,“如果在表中没有相同值的字符串,则将自己的地址注册到表中”是错的:

1String s1=new String("kvill"); 
2String s2=s1.intern(); 
3System.out.println( s1==s1.intern() ); 
4System.out.println( s1+" "+s2 ); 
5System.out.println( s2==s1.intern() );

结果: false kvill kvill true

在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。 s1==s1.intern()为false说明原来的“kvill”仍然存在;   s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。

参考资料
  • http://darrenyjy.github.io/2016/05/28/String%E6%B1%A0%E5%8C%96%E5%8F%8Aintern%E6%96%B9%E6%B3%95%E7%9A%84%E4%BD%9C%E7%94%A8/
  • http://www.debugease.com/j2se/428295.html
  • http://www.cnblogs.com/Qian123/p/5707154.html

原文发布于微信公众号 - 好好学java(SIHAIloveJAVA)

原文发表时间:2018-05-14

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏水击三千

浅谈JavaScript的面向对象程序设计(三)

  前面已经对JavaScript的面向对象程序设计作了简单的介绍,包括了对象的属性、对象的工厂模式、构造函数和原型等。通过介绍,这些创建对象的方法依然有不少优...

2315
来自专栏老九学堂

想要Java高薪,必须掌握这些基础知识点!(一)

相信很多小伙伴已经听完了徐老师的Java课程,那么Java基础的知识点你真的掌握了吗?今天就跟随老九的步伐一起来复习复习Java基础的知识点吧! ? 1、在Ja...

3306
来自专栏PHP技术

欢迎来到phpdaily

1.require和require_once用于包含库文件时更加安全。 include和include_once则适用于模板这样的操作。 require和req...

26411
来自专栏WD学习记录

C#学习笔记(四)

2. 对象之间的包含关系:一个类包含另外一个类。这类似于继承关系,但包含类可以控制对被包含类的成员的访问,甚至在使用被包含类的成员进行其他处理。

812
来自专栏Script Boy (CN-SIMO)

创建自定义类的对象数组

源代码 public class Student{ static int number = 0; // 静态变量的访问可以不用创建类的实例就可...

2020
来自专栏http://www.cnblogs.com

python学习笔记:装饰器2

python的装饰器本质是函数,为了不改变装饰目标函数内部代码而增加额外功能而存在 一.一般装饰函数实例: import datetime def func_n...

3268
来自专栏LanceToBigData

JavaSE(二)之继承、封装、多态

学习完类与对象终于认识到什么是类,什么是对象了。接下来要看的就是java的三大特征:继承、封装、多态。 一、封装(数据的隐藏) 在定义一个对象的特性的时候,有必...

1705
来自专栏乐百川的学习频道

C++ 变量和复合类型

前面说了C++的基本数据类型,下面来看看在C++中如何定义变量和常量。 变量 定义和初始化 C++定义变量的方式和C语言一样,也可以在定义的同时初始化。值得一提...

19410
来自专栏大数据学习笔记

Java程序设计(Java9版):第4章 简单复合类型

第4章 简单复合类型 4.1 数组 在C语言中,数据类型除了基本数据类型之外,还存在着大量复合数据类型。数组就是一类最简单且非常重要的复合数据类型,数组是具有相...

18210
来自专栏GreenLeaves

JavaScript之childNodes属性、nodeType属性学习

1.childNodes属性:在一颗节点树上,childNodes属性可以用来获取任何一个元素的所有元素,它是一个包含这个元素所有子元素的数组。 <body> ...

17910

扫码关注云+社区