1 String不可变性

  1. String类被声明为 final,因此它不可被继承。
  2. 内部使用char数组存储数据,该数组被声明为final,这意味着value数组初始化之后就不能再指向其它数组。
  3. String内部没有改变value数组的方法
  4. String类中所有修改String值的方法,如果内容没有改变,则返回原来的String对象引用,如果改变了,创建了一个全新的String对象,包含修改后的字符串内容,最初的String对象没有任何改变。(目的:节约存储空间、避免额外的开销)
//String的类声明以及value字段代码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
private final char value[]; //字符数组存储String的内容
/** Cache the hash code for the string */
private int hash; // Default to 0
}

不可变的验证分析:

public class Immutable {
public static String upcase(String s) {
return s.toUpperCase();
}
public static void main(String[] args) {
String q = "howdy";
System.out.println(q); // howdy
String qq = upcase(q);
System.out.println(qq); // HOWDY
System.out.println(q); // howdy
}
} /* 输出:
howdy
HOWDY
howdy
*///:~
  1. 当把q传给upcase0方法时,实际传递的是引用的一个拷贝。
  2. upcase0方法中,传入引用s,只有upcase0运行的时候,局部引用s才存在。一旦upcase0运行结束,s就消失。upcaseO的返回值是最终结果的引用。
  3. 综上,upcase()返回的引用已经指向了一个新的对象,而原本的q则还在原地。

延伸结论:

String对象作为方法的参数时,都会复制一份引用,参数传递是引用的拷贝

2 不可变的好处

1. 可以缓存 hash 值

String的hash值经常被使用,例如String用做HashMap的key。不可变的特性可以使得hash值也不可变,因此只需要进行一次计算。

2. String Pool 的需要

如果一个String对象已经被创建过了,那么就会从 String Pool 中取得引用。只有String是不可变的,才可能使用 String Pool。

3. 线程安全

String不可变性天生具备线程安全,可以在多个线程中安全地使用。

3 String+和StringBuilder效率差异

String使用“+”表示字符串拼接

先说结论:

  1. “+”操作,javac编译器会自动优化为StringBuilder.append() 调用。
  2. StringBuilder要比“+”操作高效
  3. 涉及循环追加的,手动创建StringBuilder对象操作比“+”操作编译器优化,更高效

验证:

public class StringBuilderTest {
public static void main(String[] args) {
String s1 = "ABC";
String s2 = "123";
String result = s1+s2;
System.out.println(result);
}
}

编译并查看字节码:javap -verbose StringBuilderTest.class

执行过程:

调用了2次append()方法,最后调用StringBuilder.toString()返回最终结果

为什么StringBuilder要比+高效?

  1. +操作,按照:每次追加都创建新的String对象,把字符加入value数组中。这里产生一次对象创建操作,以及对应的垃圾回收
  2. StringBuilder的底层数组value也是用到了char[],但它没有声明为final,故它可变,所以追加内容时不用创建新的数组,而是直接修改value
  3. StringBuilder比+省去String对象创建以及垃圾回收的开销,因此效率更高。

源码追溯:

 //StringBuilder.append()
@Override
public StringBuilder append(char c) {
super.append(c);
return this;
}
// 父类 AbstractStringBuilder.append()
@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
//AbstractStringBuilder value 字段
abstract class AbstractStringBuilder implements Appendable, CharSequence {
//The value is used for character storage.
char[] value; // 没有声明为final,因此value可变
}

手动实现StringBuilder对象操作比编译器自行优化,更高效

  1. 通过字节码分析可知(我这里省去了,可以自己实现验证):循环部分的代码更简短、更简单,而且它只生成了一个StringBuilder对象
  2. 显式地创建StringBuilder还允许你预先为其指定大小。如果你已经知道最终的字符串大概有多长,那预先指定StringBuilder的大小可以避免多次重新分配缓冲
当你为一个类编写toString方法时,如果字符串操作比较简单,那就可以信赖编译
器,它会为你合理地构造最终的字符串结果。但是,如果你要在toString0方法中使用循环,那
么最好自己创建一个StringBuilder对象来实现。

4 String, StringBuffer and StringBuilder

可变性

  1. String 不可变
  2. StringBuffer和StringBuilder可变

线程安全

  1. String不可变,因此是线程安全的
  2. StringBuilder 不是线程安全的
  3. StringBuffer 是线程安全的,内部使用synchronized进行同步

效率

  1. 如果要操作少量的数据用String
  2. 单线程环境且字符串缓冲区涉及大量数据 StringBuilder
  3. 多线程环境且字符串缓冲区涉及大量数据 StringBuffer

5 String与JVM内存管理

一、引入字符串常量池

  1. Javac编译后,字节码文件中有一块区域:常量池,存储了包括类中声明的字符串常量值等字面量
  2. 运行时,JVM开辟实际内存空间:字符串常量值写入了字符串常量池,属于方法区的一部分。

案例1

String s1 = "win";
String s2 = "win";
System.out.println(s1==s2);
//输出结果:true
//引用 s1 s2 的值等于win在字符串常量池的地址值

结论:

引用 s1 s2 的值等于win在字符串常量池的地址值

分析字节码的执行过程:


案例2

public class StringPool {
public static void main(String[] args) {
String s3 = new String("win");
String s4 = new String("win");
System.out.println(s3==s4);//false
}
}

结论:

通过new操作符创建的字符串对象不指向字符串池中的任何对象

字节码分析:

综上:

public class StringPool {
public static void main(String[] args) {
String s1 = "win";
String s2 = "win";
String s3 = new String("win");
String s4 = new String("win"); System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s3==s4);//false
}
}

6 String api方法

从这个表中可以看出,当需要改变字符串的内容时,String类的方法都会返回一个新的String对象。同时,如果内容没有发生改变,String的方法只是返回指向原对象的引用而已。这可以节约存储空间以及避免额外的开销。



Java基础类String学习分析的更多相关文章

  1. Java的string学习笔记 与char数组和bufferstring的比较

    ---恢复内容开始--- 一直用的C 导致这种类望而生畏 现在终于鼓起勇气学习一下 首先学习string类型 String s1 = "AbCdEf"; String s2 = & ...

  2. java中String创建对象分析(转)

    String str=new String("abc");   紧接着这段代码之后的往往是这个问题,那就是这行代码究竟创建了几个String对象呢? 相信大家对这道题并不陌生,答案 ...

  3. Java—关于String的分析

    一.两种赋值方式的比较 1.直接赋值法:String s1="abc"; 这种赋值方法用的最多,因为它可能不需要创建对象,或者只创建一次. 它首先会判断字符串常量池有没有存在字符串 ...

  4. [Java] 01 String 内存分析

    public class StringTest{ public static void main(String[] args){ String str1 = new String("123& ...

  5. Java源码学习 -- java.lang.String

    java.lang.String是使用频率非常高的类.要想更好的使用java.lang.String类,了解其源代码实现是非常有必要的.由java.lang.String,自然联想到java.lang ...

  6. 从源码分析java.lang.String.isEmpty()

    今天在写代码的时候用到了java.lang.String.isEmpty()的这个方法,之前也用过,今天突发奇想,就看了看源码,了解了解它的实现方法,总结出来,大家可以交流交流. 通常情况下,我们使用 ...

  7. Java中String连接性能的分析【转】

    [转]http://www.blogjava.net/javagrass/archive/2010/01/24/310650.html 总结:如果String的数量小于4(不含4),使用String. ...

  8. SSM框架报错分析(一)——There is no getter for property named 'XXX' in 'class java.lang.String'

    一.发现问题 <select id="queryStudentByNum" resultType="student" parameterType=&quo ...

  9. Java中String连接性能的分析

    总结:如果String的数量小于4(不含4),使用String.concat()来连接String,否则首先计算最终结果的长度,再用该长度来创建一个StringBuilder,最后使用这个String ...

  10. java中String类学习

    java中String类的相关操作如下: (1)初始化:例如,String s = “abc”; (2)length:返回字符串的长度. (3)charAT:字符操作,按照索引值获得字符串中的指定字符 ...

随机推荐

  1. 洛谷P2602 [ZJOI2010] 数字计数 (数位DP)

    白嫖的一道省选题...... 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 usin ...

  2. 洛谷P6060 [加油武汉]传染病研究

    一道不错的数学题 Solution 看到约数个数就想到枚举约数,但对于每个询问都枚举显然不现实,但是我们可以将大致的方向锁定在这方面,是否可以预处理出一定的东西,然后低复杂度询问呢? 我们想到预处理出 ...

  3. Java中的反射与代理(2)

    在经典的GoF设计模式中,有一种模式叫做代理模式,好比以前洋务运动的时候所说的「买办」,还有现在咱们经常听到的「代理人」战争中的「代理」,都是同一个意思--代替某人打理. 例如,很多北漂都找中介或者二 ...

  4. HNOI2008GT考试

    题目链接 考虑dp,f(i,j)表示做到了第i位(共n位),当前的后缀串与A1~Aj相匹配 接下来的方案数.转移的话枚举一个k=0~9表示这位选什么,如果选了以后,匹配的位置会改变到 j' ,j'可以 ...

  5. 网络工程知识(二)VLAN的基础和配置:802.1q帧;Access、Trunk、Hybrid接口工作模式过程与配置;VLANIF的小实验

    介绍-VLAN VLAN(Virtual Local Area Network)即虚拟局域网,工作在数据链路层. 交换机将通过:接口.MAC.基于子网.协议划分(IPv4和IPv6).基于策略的方式划 ...

  6. 知识图谱-生物信息学-医学顶刊论文(Bioinformatics-2021)-KG4SL:用于人类癌症综合致死率预测的知识图神经网络

    5.(2021.7.12)Bioinformatics-KG4SL:用于人类癌症综合致死率预测的知识图神经网络 论文标题:KG4SL: knowledge graph neural network f ...

  7. 【MySQL】Navicat15 安装

    # Navicat安装` 提示`:鉴于之间已经出了MySQL的安装教程,在这了我也讲下,那个其实包含了两个知识点,既可以小白初次安装MySQL客户端,也面向想安装5.x和8.x两个版本的. --- @ ...

  8. 四、redis数据类型

    四.redis数据类型 redis可以理解成一个全局的大字典,key就是数据的唯一标识符.根据key对应的值不同,可以划分成5个基本数据类型. 1. string类型: 字符串类型,是 Redis 中 ...

  9. ES6学习笔记(七)正则表达式

    正则表达式 1.基础 1.1 含义: 通俗的来讲,正则表达式是一种匹配和替换的工具.如:在JS中验证手机号时,我们需要考虑用户输入的字符必须是number类型,且必须是11位的整数,且数字的前三位必须 ...

  10. 论文笔记 - SIMILAR: Submodular Information Measures Based Active Learning In Realistic Scenarios

    motivation Active Learning 存在的重要问题:现实数据极度不平衡,有许多类别很少见(rare),又有很多类别是冗余的(redundancy),又有些数据是 OOD 的(out- ...