首页 > 其他分享 >什么是字符串常量池?

什么是字符串常量池?

时间:2022-12-08 13:07:27浏览次数:39  
标签:常量 什么 System equals String 字符串 out


链接:http://www.importnew.com/10756.html
在理解字符串常量前,我们先熟悉一下如何创建一个字符串,在Java中有两种方法可以创建一个字符串对象:

使用new运算符。例如:

String str = new String("Hello");

使用字符串常量或者常量表达式。例如:

String str="Hello"; //(字符串常量) 或者
String str="Hel" + "lo"; //(字符串常量表达式).

这些字符串的创建方式之间有什么区别呢?在Java中,equals方法被认为是对象的值进行深层次的比较,而操作符==是进行的浅层次的比较。equals方法比较两个对象的内容而不是引用。==两侧是引用类型(例如对象)时,如果引用是相同的-即指向同一个对象-则执行结果为真。如果是值类型(例如原生类型),如果值相同,则执行结果为真。equals方法在两个对象具有相同内容时返回真-但是,java.lang.Object类中的equals方法返回真-如果类没有覆盖默认的equals方法,如果两个引用指向同一个对象。

让我们通过下面的例子来看看这两种字符串的创建方式之间有什么区别吧。

public class DemoStringCreation {
public static void main(String args[]) {
String str1 = "Hello";
String str2 = "Hello";
System.out.println("str1 and str2 are created by using string literal.");
System.out.println(" str1 == str2 is " + (str1 == str2));
System.out.println(" str1.equals(str2) is " + str1.equals(str2));
String str3 = new String("Hello");
String str4 = new String("Hello");
System.out.println("str3 and str4 are created by using new operator.");
System.out.println(" str3 == str4 is " + (str3 == str4));
System.out.println(" str3.equals(str4) is " + str3.equals(str4));
String str5 = "Hel" + "lo";
String str6 = "He" + "llo";
System.out.println("str5 and str6 are created by using string constant expression.");
System.out.println(" str5 == str6 is " + (str5 == str6));
System.out.println(" str5.equals(str6) is " + str5.equals(str6));
String s = "lo";
String str7 = "Hel" + s;
String str8 = "He" + "llo";
System.out.println("str7 is computed at runtime.");
System.out.println("str8 is created by using string constant expression.");
System.out.println(" str7 == str8 is " + (str7 == str8));
System.out.println(" str7.equals(str8) is " + str7.equals(str8));
}
}

输出结果为:

str1 and str2 are created by using string literal.
str1 == str2 is true
str1.equals(str2) is true
str3 and str4 are created by using new operator.
str3 == str4 is false
str3.equals(str4) is true
str5 and str6 are created by using string constant expression.
str5 == str6 is true
str5.equals(str6) is true
str7 is computed at runtime.
str8 is created by using string constant expression.
str7 == str8 is false
str7.equals(str8) is true

使用相同的字符序列而不是使用new关键字创建的两个字符串会创建指向Java字符串常量池中的同一个字符串的指针。字符串常量池是Java节约资源的一种方式。

字符串常量池

字符串的分配,和其他的对象分配一样,耗费高昂的时间与空间代价。JVM为了提高性能和减少内存开销,在实例化字符串常量的时候进行了一些优化。为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池。如果字符串已经存在池中,就返回池中的实例引用。如果字符串不在池中,就会实例化一个字符串并放到池中。Java能够进行这样的优化是因为字符串是不可变的,可以不用担心数据冲突进行共享。例如:

public class Program
{
public static void main(String[] args)
{
String str1 = "Hello";
String str2 = "Hello";
System.out.print(str1 == str2);
}
}

其结果是:

true

不幸的是,当使用:

String a=new String("Hello");

一个字符串对象在字符串常量池外创建,即使池里存在相同的字符串。考虑到这些,要避免new一个字符串除非你明确的知道需要这么做!例如:

public class Program
{
public static void main(String[] args)
{
String str1 = "Hello";
String str2 = new String("Hello");
System.out.print(str1 == str2 + " ");
System.out.print(str1.equals(str2));
}
}

结果是:

false true

JVM中有一个常量池,任何字符串至多维护一个对象。字符串常量总是指向字符串池中的一个对象。通过new操作符创建的字符串对象不指向字符串池中的任何对象,但是可以通过使用字符串的intern()方法来指向其中的某一个。java.lang.String.intern()返回一个保留池字符串,就是一个在全局字符串池中有了一个入口。如果以前没有在全局字符串池中,那么它就会被添加到里面。例如:

public class Program
{
public static void main(String[] args)
{
// Create three strings in three different ways.
String s1 = "Hello";
String s2 = new StringBuffer("He").append("llo").toString();
String s3 = s2.intern();

// Determine which strings are equivalent using the ==
// operator
System.out.println("s1 == s2? " + (s1 == s2));
System.out.println("s1 == s3? " + (s1 == s3));
}
}

输出是:

s1 == s2? false
s1 == s3? true

为了优化空间,运行时实例创建的全局字符串常量池中有一个表,总是为池中每个唯一的字符串对象维护一个引用。这就意味着它们一直引用着字符串常量池中的对象,所以,在常量池中的这些字符串不会被垃圾收集器回收。

Java语言规范第三版中的字符串常量

每一个字符串常量都是指向一个字符串类实例的引用。字符串对象有一个固定值。字符串常量,或者一般的说,常量表达式中的字符串都被使用方法 String.intern进行保留来共享唯一的实例。

package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }

编译单元:

package other;
public class Other { static String hello = "Hello"; }

产生输出:

true true true true false true

这个例子说明了六点:

同一个包下同一个类中的字符串常量的引用指向同一个字符串对象;
同一个包下不同的类中的字符串常量的引用指向同一个字符串对象;
不同的包下不同的类中的字符串常量的引用仍然指向同一个字符串对象;
由常量表达式计算出的字符串在编译时进行计算,然后被当作常量;
在运行时通过连接计算出的字符串是新创建的,因此是不同的;
通过计算生成的字符串显示调用intern方法后产生的结果与原来存在的同样内容的字符串常量是一样的。

标签:常量,什么,System,equals,String,字符串,out
From: https://blog.51cto.com/u_14230175/5920954

相关文章

  • MySQL空间暴涨150G导致锁定,发生了什么
     背景12月1号中午突然收到大量报警,某客户环境操作数据库大量失败,报错信息如下图所示:这个报错我是第一次见,一时间有点无所适从,但是从字面意思来看是MySQL目前处于LOCK......
  • 教你如何进行数仓字符串、二进制、十六进制互转
    本文分享自华为云社区《​​GaussDB(DWS)字符串、二进制、十六进制互转​​》,作者:你是猴子请来的救兵吗。概述现网中遇到很多小伙伴不清楚字符串与进制之间的转换方法,其实......
  • 教你如何进行数仓字符串、二进制、十六进制互转
    本文分享自华为云社区《GaussDB(DWS)字符串、二进制、十六进制互转》,作者:你是猴子请来的救兵吗。概述现网中遇到很多小伙伴不清楚字符串与进制之间的转换方法,其实在Gaus......
  • 【Account Kit】华为帐号服务中回调地址的作用是什么?
    ​1、问题描述项目在测试中发现在应用服务器通过authorization_code就可以获取到access_token,id_token,refresh_token等数据。但是在文档中却是介绍通过回调获取到acces......
  • ChatGPT能做什么?ChatGPT保姆级注册教程
    最近OpenAI发布的ChatGPT聊天机器人很火,该聊天机器人可以在模仿人类说话风格的同时回答大量的问题。在现实世界之中,例如数字营销、线上内容创作、回答客户服务查询,甚......
  • 聚焦三大场景实践,读懂医疗健康业务持续增长的关键是什么!
     医疗健康业务为什么要拥抱精细化运营?如何借助数据能力构建和落地精细化运营体系?本文根据神策数据虎志强题为《数据助力医疗健康业务精细化运营》的现场演讲整理。核心内容......
  • Powershell 包含字符串
    字符串包含的三种方法 Console.WriteLine("请输入第一个字符串");           stringstr1=Console.ReadLine();           Console.WriteLine......
  • Kafka 为什么那么快?
    有人说:他曾在一台配置较好的机子上对 ​​Kafka​​ 进行性能压测,压测结果是 ​​Kafka​​ 单个节点的极限处理能力接近每秒 ​​2000万​​ 条消息,吞吐量达到每秒 ......
  • 当我们说大数据Hadoop,究竟在说什么?
    前言提到大数据,大抵逃不过两个问题,一个是海量的数据该如何存储,另外一个就是那么多数据该如何进行查询计算呢。好在这些问题前人都有了解决方案,而Hadoop就是其中的佼佼者,是......
  • android jni 字符串的处理
    说明:java中使用的是utf-16 c++中使用的utf-8;同时JNI提供一系列java和c++之间转换的方法,具体如下。extern"C"JNIEXPORTjstringJNICALLJava_com_yuanrenxue_cours......