差异点比较

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类型。

约定:

  1. 覆写equals方法时必须覆写hashcode()
  2. 如果两个对象的equals方法返回值为true,则两个object对应的HashCode值应该相同
  3. 如果两个对象的equals方法返回false,但是这两个object对应的HashCode是有可能会相同的,(但是必须意识到: HashCode返回独一无二的值,对后续存储此对象的hashtable\hashmap等容器更好的处理有很大帮助。因此覆写的时候可以考虑下hashcode的算法,尽量避免重复情况。 当然,就算出现重复,HashMap等容器也是有容错处理机制的,也是可以放入Map的,这个后续会深入分析。)

常见的几个String操作类的比较

  1. StringBuilder

线程不安全,但是性能比较高。

  1. StringBuffer

线程安全,但是性能比StringBuilder略差。因为其中的很多方法实现上都加了线程同步锁。

  1. StringTokenizer

字符串分割处理工具类。

JAVA基础5——与String相关的系列(2)的更多相关文章

  1. JAVA基础5——与String相关的系列(1)

    与String相关的系列 String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性. String类型被设置为final型,即不可继承,也就不可修改其中的实现. String可以改变吗 S ...

  2. Java基础笔记之String相关知识

    (二)String Sring 被声明为 final ,因此不可被继承. String的不可变性: 看String的定义(java9版本): public final class String imp ...

  3. Java基础-字符串(String)常用方法

    Java基础-字符串(String)常用方法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.java的API概念 Java的API(API:Application(应用) Pr ...

  4. java基础学习日志--String、StringBuffer方法案例

    package StringDemo; import java.util.Arrays; /* * 常用String.StringBufer类的方法 */ public class Demo1 { p ...

  5. 【JAVA - 基础】之String存储机制浅析

    本文主要解决以下几个问题 String源码解析? String和new String的区别? String通过"+"或concat累加时的对象创建机制? StringBuilder ...

  6. Java 基础 - 如何理解String不可变

    ref: https://www.zhihu.com/question/20618891 第一个答案. 扩展“ Java 基础 - System.arraycopy() 浅拷贝 深拷贝

  7. JAVA基础--常用类 String,StringBuffer, 基础数据类型包装类, Math类, Enum类

    字符串相关类: String, StringBuffer String类为不可变的字符序列 String s1="hello"; String s2="hello&quo ...

  8. Java基础知识总结--String、StringBuffer、StringBuilder

    1.Java String 类 String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法.在Java中,被final修饰的类是不允许被继承的,并且该类中 ...

  9. Java基础--常用API--日期相关API

    一.java.util.Date 1.只用于显示系统时间,其大部分操作由Calendar代替. 格林威治时间(GMT):指的是1970年1月1日0时,不同地区有时间差. 默认输出格式:星期.月.日.时 ...

随机推荐

  1. redis3.2新功能--GEO地理位置命令介绍

    概述 redis3.2发布rc版本已经有一段时间了,估计RedisConf 2016左右,3.2版本就能release了.3.2版本中增加的最大功能就是对GEO(地理位置)的支持.说起redis的GE ...

  2. LDAP服务部署

    1.安装基本环境 # yum -y install openldap openldap-devel openldap-servers openldap-clients 2.配置LDAP服务端 (1)拷 ...

  3. WordPress 4.8 安装配置教程 (基于 centos 7.3, php 7.0, mysql 5.7.19, nginx 1.12.1)

    最近想要整个 blog,记录自己工作.学习中的点滴.Wordpress 自然是首选,因为内容才是关键,所以也就不怕别人说太 low.网上大部份都是讲 wordpress 配合 apache 的安装教程 ...

  4. 237. Delete Node in a Linked List(leetcode)

    Write a function to delete a node (except the tail) in a singly linked list, given only access to th ...

  5. C#,COM口,接收,发送数据

    这里写一种,COM口的数据接收,发送方法. 1.COMHelper类 /// <summary>初始化串行端口</summary> private SerialPort _se ...

  6. [译]ASP.NET Core 2.0 会话状态

    问题 如何在ASP.NET Core 2.0中存储会话状态? 答案 创建一个空项目,修改Startup类的ConfigureServices()方法,添加会话状态服务和它后台的存储服务: public ...

  7. Redis主从环境配置

    1.Redis主从同步原理 redis主服务器会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,然后将数据文件同步给从服务器,从服务器加载记录文件,在内存库中更新新数据. 2.VMWar ...

  8. .2-Vue源码起步(2)

    接着第一节开始继续吧(GoGoGo) 上一节把mergeOptions函数弄完了,最后返回一个options赋给了vm.$options. 这一节继续跑代码: function initMixin(V ...

  9. css3+div画大风车

    今天已经礼拜三了,周天小颖家的佩佩就要结婚啦,小颖要去当伴娘了,哈哈哈哈哈哈,想想都觉得乐开了花,不过之前她给我说让我当她伴娘时,我说我要减肥,不然她那么瘦弱,我站旁边就感觉像一个圆滚滚的小皮球,小颖 ...

  10. 从架构演进的角度聊聊Spring Cloud都做了些什么?

    Spring Cloud作为一套微服务治理的框架,几乎考虑到了微服务治理的方方面面,之前也写过一些关于Spring Cloud文章,主要偏重各组件的使用,本次分享主要解答这两个问题:Spring Cl ...