JAVA基础5——与String相关的系列(2)
差异点比较
String使用+直接拼接
这种情况需要分两种情况来讨论:
1、 都是确定的字符串常量之间进行的+号拼接的时候,由于在编译器就可以确定其具体值了,所以编译器在编译期的时候就会把这些常量拼接的字符串解析为一个整的字符串常量。举例如下:
String s1="helloworld";
String s2="hello" + "word";
System.out.println( s1==s2 );
执行结果:
true (可以看出s0跟s1是同一个对象,因为编译期的时候s2就已经被解析为helloworld了)
2、 不确定的变量之间使用+拼接的时候,由于编译器无法在编译期进行优化,只能在运行期动态分配处理。举例如下:
String s1 = "a";
String s2 = "b";
String s3 = "c";
String s4 = s1 + s2 + s3;
String s5 = "a" + "b" + "c";
System.out.println( s4==s5 );
执行结果:
false (因为s5编译期就确定为一个常量,而s4运行期动态分配)
s4的JDK层实现逻辑如下:
StringBuffer temp = new StringBuffer();
temp.append(s1).append(s2).append(s3);
String s = temp.toString();
由JDK层的实现代码可以看出,每执行一次+操作,就会生成一个StringBuffer对象,然后生成一个新的字符串对象。因此,如果是for循环中对多个字符串进行拼接的时候,可以直接使用StirngBuffer或者StringBuilder进行append操作,可以减少N-1次StringBuffer对象的创建。
3、 final修饰的字符串变量,在编译的时候也会被当做常量进行优化,如下所示:
String s0 = "ab";
final String s1 = "b";
String s2 = "a" + s1;
String s3 = "b";
String s4 = "a" + s3;
System.out.println((s0 == s2));
System.out.println((s0 == s4));
执行结果:
true
false
因为s1是final型的,所以编译期会被当做确定常量,s2直接编译期被优化为ab,而s3只是普通变量,无法编译期优化,所以按照字符串拼接的方式,会生成新的字符串对象。
关于String不同操作过程生成几个对象的问题
关键点:对于字符串字面量的形式(即双引号的方式),只有当字符串常量池中不存在相同的字符串的时候才会创建;对于new的方式一定会有新对象产生。
1、 String s = "abc"创建了几个对象?
这个语句创建了一个对象或者0个对象,取决于abc这个字符串是否已经在常量池中存在。
2、 String s = new String("abc")创建了几个对象?
这个语句等价于下面的语句:
String param = "abc";
String s = new String(param);
因此,这个过程一共创建了两个对象或者一个对象,即param与s(取决于常量池中是否已经有abc字符串了)。
3、 String s1 = "abc"; String s2 = "abc"创建了几个对象?
这个情况也是只创建了一个对象或者0个对象"abc",然后s1和s2都只是指向同一个"abc"内存地址的引用,如果"abc"已经在常量池中的时候,就不会新创建。
4、 String s = "a" + "b"创建了几个对象?
这个实际上与String s = "ab"是等价的,这个过程新创建了1个对象或者0个对象。
5、 String c = "xx" + "yy " + a + "zz" + "mm" + b创建几个对象?
这个语句编译优化后等价于下面的逻辑:
String c = (new StringBuilder().append("xxyy").append(a).append("zz").append("mm").append(b)).toString();
即:如果+进行拼接的时候,从左往右,会将最初的几个常量都直接合并为1个常量(比如xx和yy),然后与变量进行拼接,然后出现在变量后面的常量就没法再合并到一起了(比如zz和mm),只能逐个累加。
此过程中,会产生1个StringBuilder对象和一个String对象。
关于==与equals以及HashCode
简而言之,==用于比较简单的数据类型,或者看下某两个对象引用是否指向堆内存中的同一块地址;equals用于比较两个对象的内容是否相同。
对于Object对象而言,其默认提供的equals方法实现就是简单的return this == obj;即只有两个对象都指向了同一个内存地址对象的时候,才会return true。 对于需要比较内容是否相等的情况时,必须要自行覆写equals方法。
对于覆写equals方法的时候,通常要求必须同时覆写HashCode()方法。hashCode即对象的散列码,int类型。
约定:
- 覆写equals方法时必须覆写hashcode()
- 如果两个对象的equals方法返回值为true,则两个object对应的HashCode值应该相同
- 如果两个对象的equals方法返回false,但是这两个object对应的HashCode是有可能会相同的,(但是必须意识到: HashCode返回独一无二的值,对后续存储此对象的hashtable\hashmap等容器更好的处理有很大帮助。因此覆写的时候可以考虑下hashcode的算法,尽量避免重复情况。 当然,就算出现重复,HashMap等容器也是有容错处理机制的,也是可以放入Map的,这个后续会深入分析。)
常见的几个String操作类的比较
- StringBuilder
线程不安全,但是性能比较高。
- StringBuffer
线程安全,但是性能比StringBuilder略差。因为其中的很多方法实现上都加了线程同步锁。
- StringTokenizer
字符串分割处理工具类。
JAVA基础5——与String相关的系列(2)的更多相关文章
- JAVA基础5——与String相关的系列(1)
与String相关的系列 String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性. String类型被设置为final型,即不可继承,也就不可修改其中的实现. String可以改变吗 S ...
- Java基础笔记之String相关知识
(二)String Sring 被声明为 final ,因此不可被继承. String的不可变性: 看String的定义(java9版本): public final class String imp ...
- Java基础-字符串(String)常用方法
Java基础-字符串(String)常用方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.java的API概念 Java的API(API:Application(应用) Pr ...
- java基础学习日志--String、StringBuffer方法案例
package StringDemo; import java.util.Arrays; /* * 常用String.StringBufer类的方法 */ public class Demo1 { p ...
- 【JAVA - 基础】之String存储机制浅析
本文主要解决以下几个问题 String源码解析? String和new String的区别? String通过"+"或concat累加时的对象创建机制? StringBuilder ...
- Java 基础 - 如何理解String不可变
ref: https://www.zhihu.com/question/20618891 第一个答案. 扩展“ Java 基础 - System.arraycopy() 浅拷贝 深拷贝
- JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类
字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...
- Java基础知识总结--String、StringBuffer、StringBuilder
1.Java String 类 String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法.在Java中,被final修饰的类是不允许被继承的,并且该类中 ...
- Java基础--常用API--日期相关API
一.java.util.Date 1.只用于显示系统时间,其大部分操作由Calendar代替. 格林威治时间(GMT):指的是1970年1月1日0时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...
随机推荐
- C# 相对路径转绝对路径
如果是路径相对路径,使用 Path 转换 System.IO.Path.Combine(文件夹, relativePath); 文件夹就是相对的文件夹. 这样就可以把相对路径转绝对. 参见:http: ...
- 自学jQueryMobile之简单创建页面
首先简答介绍一下JQueryMobile吧,我觉得用一句话来讲就是可以 "写更少的代码,做更多的事情" : 它可以通过一个灵活及简单的方式来布局网页,且兼容所有移动设备.这也是我自 ...
- C语言 数组名不是指针
今天上计算机系统课的时候老师讲到了C中的聚合类型的数据结构.在解释数组名的时候说"数组名是一个指针,指向该数组的第一个元素",附上ppt(第二行): 我觉得这是不正确的,是一个常见 ...
- LeetCode 543. Diameter of Binary Tree (二叉树的直径)
Given a binary tree, you need to compute the length of the diameter of the tree. The diameter of a b ...
- JS插入新的节点
insertBefore() 语法: insertBefore(newchild,refchild) newchild 插入新的节点 refchild 在此节点前插入新节点 <ul id=&qu ...
- python自动化运维七:fabric
p { margin-bottom: 0.25cm; line-height: 120% } a:link { } p { margin-bottom: 0.25cm; line-height: 12 ...
- 京东口红top 30分析
一.抓取商品id 分析网页源码,发现所有id都是在class="gl-item"的标签里,可以利用bs4的select方法查找标签,获取id: 获取id后,分析商品页面可知道每个商 ...
- 一行python的强大功能
能够把自身代码打印出来的程序,叫做Quine. 下面是python的一行quine: _='_=%r;print _%%_';print _%_ 有人说有分号不算一行,无分号版: print(lamb ...
- runtime--小白看过来
目录 RunTime 概述 RunTime消息机制 RunTime交换方法 RunTime消息转发 RunTime关联对象 RunTime实现字典与模型互转 1.RunTime 概述 我们在面试的时候 ...
- QT信号和槽
QT信号和槽 ============ 信号和槽是一种高级接口,应用于对象之间的通信,它是 QT 的核心特性.要正确的处理信号和槽,必须借助一个称为 moc(Meta Object Compiler) ...