String类的迷惑之解

package test;

public class StringTest {
 /**
  * @param args
  * @author dougq
  */
 public static void main(String[] args)
 {
  String a = "xyz";
  String b= "xyz";
  System.out.println(a==b); 
  
  String a2 = new String("xyz");
  String b2= new String("xyz");
  System.out.println(a2==b2); 
  
 }
}

Result:

true
false

到网上查了好些资料,最终觉得下面这篇文章是一个最为满意的答复,全文如下:

全面理解Java中的String数据类型

    1. 首先String不属于8种基本数据类型,String是一个对象。 

  因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。 

  2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null; 

  3. String str=”kvill”; 
String str=new String (“kvill”);的区别: 

  在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。 

  常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。 

  看例1: 


String s0=”kvill”; 
String s1=”kvill”; 
String s2=”kv” + “ill”; 
System.out.println( s0==s1 ); 
System.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: 

String s0=”kvill”; 
String s1=new String(”kvill”); 
String s2=”kv” + new String(“ill”); 
System.out.println( s0==s1 ); 
System.out.println( s0==s2 ); 
System.out.println( s1==s2 ); 

  结果为: 
false 
false 
false 

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

  4. String.intern(): 

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

  例3: 

String s0= “kvill”; 
String s1=new String(”kvill”); 
String s2=new String(“kvill”); 
System.out.println( s0==s1 ); 
System.out.println( “**********” ); 
s1.intern(); 
s2=s2.intern(); //把常量池中“kvill”的引用赋给s2 
System.out.println( s0==s1); 
System.out.println( s0==s1.intern() ); 
System.out.println( s0==s2 ); 


  结果为: 

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

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

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

  看例4: 

String s1=new String("kvill"); 
String s2=s1.intern(); 
System.out.println( s1==s1.intern() ); 
System.out.println( s1+" "+s2 ); 
System.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。 

  5. 关于equals()和==: 

  这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。 

  6. 关于String是不可变的

  这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”kv”+”ill”+” “+”ans”; 
就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” “ 生成 ”kvill “存在内存中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。

 
角色 你是一名PYTHON高级开发工程师 需求 输出质量相关的PYTHON试题(请生成性能效率的),分别来自四个方面,每个方向输出1个题目;总体要求:2个多选,1个单选,1个无问题。难易程度穿插开就行。 如下: 质量属性 代码问题 难易程度 题型 Functional Suitability(功能性):需求实现偏差是线上缺陷主要原因(如空值处理缺失) 有问题 中等 多选 困难 单选 容易 单选 无问题 困难 多选 Maintainability(可维护性):可读性,重复度,耦合性 有问题 中等 多选 困难 单选 容易 单选 无问题 困难 多选 Performance Efficiency(性能效率):关注算法复杂度与资源泄漏(如数据库连接未关闭) 有问题 中等 多选 困难 单选 容易 单选 无问题 中等 多选 Reliability(可靠性):异常处理缺陷(如空指针捕获缺失)与并发竞态条件 有问题 中等 多选 困难 单选 容易 单选 无问题 中等 多选 输出格式 1、问题代码 说明:"存在0个及以上问题的代码,可同时存在多种型问题;能明确指出问题所在行。每行的格式为:行号(int型)+空格+代码" 代码样例: 2、问题选项 说明:"多个答案选项。每个选项基本格式为:''第""+问题起始行号+~+问题终止行号+""行""+英文逗号+问题描述。 单选题有3个选项+未发现问题“选项,其中有一个正确答案。多选题存在5个选项,其中有2个及以上正确答案" 3、问题答案 说明:"多选为A,B,中间为英文逗号。单选为单个字母" 4、质量属性 说明:功能性,性能效率,可维护性,可靠性中的任意一个 输出样例 1、问题代码: "...... 13 func NewScriptExecutor(cmd string, args ...string) *Executor{ 14 var script []string 15 script = append(script, cmd) 16 script = append(script, args...) 17 return &Executor{ 18 name: cmd, 19 mold: ""script"", 20 script: script, 21 } ......." 2、问题选项: "单选: 该代码存在什么问题? A. 第35行,存在内存泄漏 B. 第68行,存在越界异常 C. 第9~11行,存在空指针异常 D. 未发现问题 多选: A. 第11行,缺少对代码的功能描述的注释 B. 第23行,缺少对变量的命名说明 C. 第2021行,缺少对函数返回值的描述 D. 第2530行,缺少对库的引用说明 E. 第32~35行,存在越界异常" 3、问题答案: 单选:A 多选:A,B,C 4、质量属性: 可靠性
03-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

韩立凡人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值