热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Java中关于String问题的总结

Java面试中总喜欢出几个关于String对象的题,比如:1.StringsnewString(abc);创建了几个String对象。2.Strin

Java面试中总喜欢出几个关于String对象的题,比如:

1.String s = new String("abc");创建了几个String对象。

2.String s1 = "abc";
   String s2 = "a";
   String s3 = s2 + "bc";
   String s4 = "a" + "bc";
   String s5 = s3.intern();
请问s1==s3是true还是false,s1==s4是false还是true。s1==s5呢?

这样的题碰到很多了,今天来全面的总结一下,之所以敢说全面,是因为我参考的是最权威的资料……Java语言规范和Java API。

API中说明:

字符串是常量;它们的值在创建之后不能更改。因为 String 对象是不可变的,所以可以共享。(http://gceclub.sun.com.cn/Java_Docs/jdk6/html/zh_CN/api/java/lang/String.html)

那么,是如何共享的勒,String类的intern方法有如下说明:

字符串池,初始为空,它由类 String 私有地维护。(http://gceclub.sun.com.cn/Java_Docs/jdk6/html/zh_CN/api/java/lang/String.html#intern())

也就是说,String类自己维护了一个池,把程序中的String对象放到那个池里面,于是我们代码中只要用到值相同的String,就是同一个String对象,节省了空间。

但是,并不是任何时候任何String对象都在这个字符串池中,不然也就不会有那些面试题了。那么,到底哪些String对象在池中,哪些在堆中?请看Java语言规范。

Java语言规范第三版,第3.10.5小节,String Literals的最后一段如下:

 

Literal strings within the same class (§8) in the same package (§7) represent references to the same String object (§4.3.1).

Literal strings within different classes in the same package represent references to the same String object.

Literal strings within different classes in different packages likewise represent references to the same String object.

Strings computed by constant expressions (§15.28) are computed at compile time and then treated as if they were literals.

Strings computed by concatenation at run time are newly created and therefore distinct.

The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

以上6句话就是权威且全面的解释了。我依次解释下。

首先解释下什么是字符串字面常数(String Literals),字面常数(Literals)就是你写在源代码里面的值,比如说int i = 6; 6就是一个整数形字面常数。String s = "abc"; “abc”就是一个字符串字面常数。Java中,所有的字符串字面常数都放在上文提到的字符串池里面,是可以共享的,就是说,String s1 = "abc"; String s2 = "abc"; s1,s2都引用的同一个字符串对象,而且这个对象在字符串池里面,因此s1==s2。另外,字符串字面常数是什么时候实例化并放到字符串池里面去的呢?答案是Load Class的时候(Java Spec 12.5)。

下面看那6句话。

前面三句基本废话,想绕口令一样,意思就是说任何类任何包,值相同的字符串字面常数(String Literals)都引用同一个对象。

第四句是说,通过常量表达式(constant expressions)计算出来的字符串,也算字符串字面常数,就是说他们也在字符串池中。什么是常量表达式(constant expressions)待会说,这个很重要。

注意第五句话,在程序运行时通过连接(+)计算出来的字符串对象,是新创建的,他们不是字面常数,就算他们值相同,他们也不在字符串池里面,他们在堆内存空间里,因此引用的对象各不相同。

最后一句话也很重要,String类的intern方法,返回一个值相同的String对象,但是这个对象就像一个字符串字面常数一样,意思就是,他也到字符串池里面去了。

现在我们来看开头的两个题目。

 

1.String s = new String("abc");创建了几个String对象。

答案是2个,一个是字符串字面常数,在字符串池中。一个是new出来的字符串对象,在堆中。

2.String s1 = "abc";
   String s2 = "a";
   String s3 = s2 + "bc";
   String s4 = "a" + "bc";
   String s5 = s3.intern();
请问s1==s3是true还是false,s1==s4是false还是true。s1==s5呢?

此题注意两点,因为s2是一个变量,所以s3是运行时才能计算出来的字符串,是new的,在堆中不在字符串池中。s4是通过常量表达式计算出来的,他等同于字符串字面常数,在字符串池中。所以,s1!=s3,s1==s4。再看s5,s5是s3放到字符串池里面返回的对像,所以s1==s5。这里新手要注意的是,s3.intern()方法,是返回字符串在池中的引用,并不会改变s3这个变量的引用,就是s3还是指向堆中的那个"abc",并没有因调用了intern()方法而改变,实际上也不可能改变。

好,现在我们回到前文没有说清楚的一个问题,到底什么算常量表达式(constant expressions)。上面提到了两种非常量表达式,new 和变量相加。至于什么算常量表达式(constant expressions),请看Java语言规范。

 

15.28 Constant Expression

ConstantExpression: Expression

A compile-time constant expression is an expression denoting a value of primitive type or a String that does not complete abruptly and is composed using only the following:

  • Literals of primitive type and literals of type String 
  • Casts to primitive types and casts to type String
  • The unary operators +-~, and (but not ++ or --)
  • The multiplicative operators */, and %
  • The additive operators + and -
  • The shift operators <<>>, and >>>
  • The relational operators <<&#61;>, and >&#61; (but not instanceof)
  • The equality operators &#61;&#61; and !&#61;
  • The bitwise and logical operators &^, and |
  • The conditional-and operator && and the conditional-or operator ||
  • The ternary conditional operator ? :
  • Parenthesized expressions whose contained expression is a constant expression.
  • Simple names that refer to constant variables
  • Qualified names of the form TypeName . Identifier that refer to constant variables

Compile-time constant expressions are used in case labels in switch statements and have a special significance for assignment conversion. Compile-time constants of type String are always "interned" so as to share unique instances, using the method String.intern.

A compile-time constant expression is always treated as FP-strict, even if it occurs in a context where a non-constant expression would not be considered to be FP-strict.

看着是不是有点晕&#xff0c;这情况也太多了&#xff0c;面试应该不会那么变态的。其实看着复杂&#xff0c;记住一个原则就好了&#xff0c;那就是编译时能确定的&#xff0c;就算&#xff0c;运行时才能确定的&#xff0c;就不算。以下为例子

String s &#61; 1 &#43; "23";//算&#xff0c;符合第二条Casts to primitive types and casts to type String
String s &#61; (2 > 1) &#43; "" ;//算&#xff0c;意味着s&#61;&#61;"true"&#xff0c;且这个“true”已经放到字符串池里面去了。
String s &#61; (o instanceof Object) &#43; "";//不算&#xff0c;instanceof这个操作符决定了不算。s&#61;&#61;"true"&#xff0c;但这个"true"对象在堆中。

留意下面的情况。

   final String s2 &#61; "a";
   String s3 &#61; s2 &#43; "bc";//算

注意现在的s2&#43;"bc"也算一个常量表达式&#xff0c;理由是那个列表里面的最后两条&#xff0c;s2是一个常量变量(constant variables)&#xff0c;问题又来了&#xff0c;什么是常量变量&#xff1f;规范里也说了&#xff0c;被final修饰&#xff0c;并且通过常量表达式初始化的变量&#xff0c;就是常量变量。变量s2被final修饰&#xff0c;他通过常量表达式"a"初始化&#xff0c;所以s2是一个常量变量&#xff0c;所以s3引用的"abc"&#xff0c;也在字符串池里面咯&#xff0c;明白了吧。

再举个反例&#xff1a;

final String s2 &#61; getA();//s2不是常量变量&#xff0c;但是s2引用的"a"其实还是在常量池中&#xff0c;这两点不矛盾
public String getA(){return "a"}

String s3 &#61; s2 &#43; "bc";//此时s3不算常量表达式&#xff0c;因为s2不是常量变量

这是时候的s2&#xff0c;就不是常量变量了哦&#xff0c;因为getA()不是一个常量表达式

 转自&#xff1a;http://blog.51cto.com/cymoft/473220

转:https://www.cnblogs.com/leilong/p/8646912.html



推荐阅读
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • ALTERTABLE通过更改、添加、除去列和约束,或者通过启用或禁用约束和触发器来更改表的定义。语法ALTERTABLEtable{[ALTERCOLUMNcolu ... [详细]
  • Java自带的观察者模式及实现方法详解
    本文介绍了Java自带的观察者模式,包括Observer和Observable对象的定义和使用方法。通过添加观察者和设置内部标志位,当被观察者中的事件发生变化时,通知观察者对象并执行相应的操作。实现观察者模式非常简单,只需继承Observable类和实现Observer接口即可。详情请参考Java官方api文档。 ... [详细]
  • 本文介绍了OpenStack的逻辑概念以及其构成简介,包括了软件开源项目、基础设施资源管理平台、三大核心组件等内容。同时还介绍了Horizon(UI模块)等相关信息。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文详细介绍了Spring的JdbcTemplate的使用方法,包括执行存储过程、存储函数的call()方法,执行任何SQL语句的execute()方法,单个更新和批量更新的update()和batchUpdate()方法,以及单查和列表查询的query()和queryForXXX()方法。提供了经过测试的API供使用。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 前景:当UI一个查询条件为多项选择,或录入多个条件的时候,比如查询所有名称里面包含以下动态条件,需要模糊查询里面每一项时比如是这样一个数组条件:newstring[]{兴业银行, ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • 预备知识可参考我整理的博客Windows编程之线程:https:www.cnblogs.comZhuSenlinp16662075.htmlWindows编程之线程同步:https ... [详细]
author-avatar
手机用户2602914917
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有