字符串比较问题的内部分析

字符串比较


Step1



我在CDSN论坛上看到这样一个帖子,觉得挺不错的,自己在这方面也正在学,于是乎去尝试了一下,问题截图如下:

原帖链接:http://bbs.csdn.net/topics/391957440

下面是那位贴出问题的博友,在得到网友回答后写出的总结:

1: 对于 String str3 = “JavaEE” + “Android”;这条语句会在编译时期确定,如果常量池中有 “JavaEEAndroid”则会将这个字符串的地址放到str3中。

如果没有,则会在常量池中新建,然后赋值引用。

2: 对于 str1= str1 + “Android”; 在编译时并没有确定,只有在运行时才能确定值。所以会在堆中新建对象String 类型 然后赋值给str1;

这样str1 所引用的地址并不是”JavaEEAndroid”的地址。所以不相等。


Step2



我拿到这个问题后,也学着我之前看视频的老师那样,画画内部原理图,如下:

等我画完才发现,从我这样画的原理图,最终str1与str3应该是一样的地址引用值才对,可结果 str1 == str3 为 false,就说明这里str1与str3实际上是不等的。

于是又折腾了一晚上,等到第二天才算是将其弄清楚,见下图。


Step3



以下是我的见解:

下面是一个Java字符串连接的例子:

String one = "Hello";
String two = "World";
String three = one + " " + two;

编译器最终会把上面的代码编译为类似下面的代码:

String one = "Hello";
String two = " World";

String three = new StringBuilder(one).append(two).toString();

此代码实际上创建了两个对象:一个StringBuilder实例,然后从toString()方法返回一个新的String实例。

@Override
public String toString() {
    // Create a copy, don‘t share the array
    return new String(value, 0, count);
}

此处最终得到的是new 出来的一个String实例,进而会在堆中开辟一个空间,继而String 的引用result 会指向这个新开辟的起始地址



仍需注意的是,上例中StringBuilder()和append()传进去的参数是String类型的,当定义的String类型被如下final修饰的时候,str1直接就是常量了:

@Test
public void Test01(){
    final String str1 = "JavaEE";
    String str = str1 + "Android";
    String str3 = "JavaEEAndroid";
    System.out.println(str3 == str);//true
    System.out.println(str3.equals(str));//true
}

此处str3 与 str1就不会像第一例那样调用StringBuilder进行字符串的串联,而是直接相连接存入到常量池中


Step4



总结:这里理解的重点是,在字符串用’+‘号串联时,什么时候用” new StringBuilder(one).append(two).toString();”的形式,什么时候直接相连,

关键看’+‘号两侧的字符串是变量还是常量,若都为String类型的引用变量,则必定是调用StringBuilder方法,若存在声明为final的常量,则直接相连,

补充一点:前者是在堆中重新开辟一个存储空间,用来存储指向常量池中该字符串的首地址;而后者是直接在堆常量池中创建串联后的新字符串(若池中

原先就存在了,就直接用原来的)

时间: 2024-10-15 00:44:37

字符串比较问题的内部分析的相关文章

字符串转换数值类型异常分析

在这篇文章中,我们来分析一下C#的函数int.Parse(),字符串转换数值类型时候发生的异常. int.Parse(String str): 这种方法是将数字内容的字符串转换为int类型. 如果字符串的内容为Null ,则抛出ArgumentNullException异常: 如果字符串内容不是数字,则抛出FormatException异常. 使用该方法只能处理字符串的内容,而且转换后的字符串内容要在int类型的可表示范围之内. 好,现在来一段测试程序: 这是测试界面 输入int32表示范围内的

几种常见的字符串连接方法连接速度分析

在平时的开发中难免会遇到字符串拼接的情况.比较常用的方法有:StringBuilder,+运算符,string.Format和string.Concat. 在.NET程序员中一直流传着一个传说:StringBuilder的性能可以吊打+运算符.不知道大家有没有亲自测试过这个传说,反正我以前没有没测试过. 通过查看源代码可以发现string.Format是通过调用StringBuilder中的方法来实现字符串拼接的.而且相对来说string.Format对字符串的格式很友好.所以在平时的开发中我最

关于Boost,C Regex对短目标字符串正则匹配的性能分析

昨天对长目标字符串下的各种正则匹配库性能进行了总结,得出结论是Boost regex性能最佳.今天将其应用到项目当中,果不其然,长字符串匹配带来的性能损失基本没有了,当然,目前规模并不算太大,但是在可预计规模内Boost可以完全达到要求. 不过有一点,在Boost,C同时去除长字符串匹配的影响后,剩下都是短字符串匹配,发现Boost比C好的并不是好很多,例如10000+次短字符匹配中,其中包含匹配成功和不成功的,Boost regex+系统其他模块用时130ms左右,而C regex+系统其他模

python初学day2--(字符串(str)内部功能简介)

Str内部功能简介 1,pitalize(self): 将字符串首字母变成大写 s = 'hello' result = s.capitalize() print(result)              结果: Hello 2,casefold(self): 见字符串变成小写 s = 'HELLO' result = s.casefold() print(result)      结果:hello 3,center(self, width, fillchar=None):经字符串居中,默认用空

python字符串-内置方法用法分析

1.字母大小写相关(中文无效) 1.1 S.upper() -> string 返回一个字母全部大写的副本 1.2 S.lower() -> string 返回一个字母全是小写的副本 1.3 S.swapcase() -> string 返回一个字母大小写转换后的副本 1.4 S.title() -> string 将单词的首字母大写,即为所谓的标题 方框里是中文的编码,可以发现 s 还是大写了,说明会无视其他类型的字符,找到英文单词就将其首字母大写 1.6 S.capitaliz

Windbg DUMP分析(原创汇总)

1. 引入篇 1.1 下载安装 1.2 调试器 1.3 操作界面2. 命令篇 2.1 按照来源划分 2.1.1 基本命令 2.1.2 元命令 2.1.3 扩展命令 2.2 按照功能划分 2.2.1 系统信息 2.2.2 进程 2.2.3 模块 2.2.4 符号 2.2.5 线程 2.2.6 内存 2.2.7 事件3. 探讨篇 3.1方法内联 3.2 字符串驻留池 1. 引入篇 引入篇 1.1 下载安装 1.2 调试器 1.3 操作界面 所谓技术分享,其实是一个自我总结和相互学习.不断成长的过程.

JQuery选择器中含有冒号的ID处理差异的分析

问题提出 对于一个输入框, 如果其id中含有冒号(:),选择器使用需要有特殊写法, 例如 id为下 <input type="text" value="ddd" id="a:b"> 使用$(selector)直接使用#id值, 找不到DOM console.log("#a:b")console.log($("#a:b").length) // output 0 经过探索可以使用以下两个方法选择到

MapReduce源码分析之MapTask分析(二)

SpillThread分析 为什么需要Spill 内存大小总是有效,因此在Mapper在处理过程中,数据持续输出到内存中时,必然需要有机制能将内存中的数据换出,合理的刷出到磁盘上.SpillThread就是用来完成这部分工作. SpillThread的线程处理函数只是做一层封装,当索引表中的kvstart和kvend指向一样的索引位置时,会持续处于等待过程,等待外部通知需要触发spill动作,当有spill请求时,会触发StartSpill来唤醒SpillThread线程,进入到sortAndS

[Java] 数组声明有关问题分析

问题 最近在CSDN论坛上闲逛的时候,看见有朋友在询问一些基础的知识点,而恰好最近我一直在学Java基础部分,因此我从内存的角度试着总结了一下有数组声明有关问题 @Test public void Test(){ String[] p = null; p = {"no"};//这种不指定数组下标初始化的方式只在下一行这种格式中适用 String[] s = new String[]{"no"}; p[0] = "y";//此处编译可以通过,但是运