String复习

概述

String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承)

在 Java 8 中,String 内部使用 char 数组存储数据。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
}

在 Java 9 之后,String 类的实现改用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码。

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final byte[] value;

    /** The identifier of the encoding used to encode the bytes in {@code value}. */
    private final byte coder;
}

value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。

不可变的好处

1. 可以缓存 hash 值

字符串广泛应用于 HashMap、HashTable、HashSet 等需要哈希码作为键的数据结构中,在对这些哈希表进行操作的时候,需要频繁调用 hashCode() 方法来获取键的哈希码。

由于字符串是不可变性,这就保证了键值的哈希值不会发生改变,因此在第一次调用 String 类的 hashCode() 方法时,就对哈希值进行了缓存,此后,就一直返回相同的值。由于哈希值被缓存了,这在另外一种层面上提高了哈希表的访问性能,因为哈希值不用重新计算了。

2. String Pool的需要

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

2.1 设计思想

  • 为字符串开辟一个字符串常量池,类似于缓存区
  • 创建字符串常量时,首先坚持字符串常量池是否存在该字符串
  • 存在该字符串,返回引用实例,不存在,实例化该字符串并放入池中

2.2 堆、栈、方法区

在这里插入图片描述
2.2.1 堆

存储的是对象,每个对象都包含一个与之对应的class

JVM只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身

对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定

2.2.2 栈

每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象)

每个栈中的数据(原始类型和对象引用)都是私有的

栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)

数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失

2.2.3 方法区

静态区,跟堆一样,被所有的线程共享

方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量
字符串常量池则存在于方法区

3 安全性

字符串在 Java 应用程序中的使用范围非常广,几乎无处不在,比如说存储用户名、密码、数据库连接地址等等这些非常敏感的信息,因此,必须要保证 String 类的绝对安全性。

4. 线程安全

由于字符串是不可变的,因此可以在多线程之间共享,如果一个线程把字符串的值修改为另外一个,那么就会在字符串常量池中创建另外一个字符串,原有的字符串仍然会保持不变。

String, StringBuffer and StringBuilder

1.可变性

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

2 线程安全

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

String Pool

字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。

当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

    String str1 = “abc”;
    String str2 = “abc”;
    String str3 = “abc”;
    String str4 = new String(“abc”);
    String str5 = new String(“abc”);
    String str6 = new String(“abc”);
在这里插入图片描述

面试题:String str4 = new String(“abc”) 创建多少个对象?

  • 在常量池中查找是否有“abc”对象,有则返回对应的引用实例, 没有则创建对应的实例对象
  • 在堆中 new 一个 String("abc") 对象
  • 将对象地址赋值给str4,创建一个引用

所以,常量池中没有“abc”字面量则创建两个对象,否则创建一个对象,以及创建一个引用

根据字面量,往往会提出这样的变式题:

  • String str1 = new String("A"+"B") ; 会创建多少个对象?
  • String str2 = new String("ABC") + "ABC" ; 会创建多少个对象?

str1:
字符串常量池:"A","B","AB" : 3个
堆:new String("AB") :1个
总共 : 4个

str2:
字符串常量池:"ABC" : 1个
堆:new String("ABC") :1个
总共:2个

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 基本 我们先来看一下String在Jdk中的定义 我们发现这是一个String类被finl进行修饰了,name就可...
    忒无聊了叭阅读 269评论 0 0
  • 前言 String 是Java语言非常基础和重要的类,提供了构造和管理字符串的各种基本逻辑。它是典型的 Immut...
    _Zy阅读 761评论 0 3
  • String 是Java编程中的引用类型,不属于基本类型,默认值为null,在Java中是用来创建于操作字符串。源...
    小杰的快乐时光阅读 559评论 0 1
  • 本文主要介绍Java中与字符串相关的一些内容,主要包括String类的实现及其不变性、String相关类(Stri...
    Keaper阅读 304评论 0 0
  • 前言 RTFSC (Read the fucking source code )才是生活中最重要的。我们天天就是要...
    二毛_coder阅读 466评论 1 1