设为首页 加入收藏

TOP

String详解(一)
2023-07-25 21:43:47 】 浏览:80
Tags:String 详解

String对象的不可变原因,String对象的内存布局,及String对象之间的执行==equals+运算时的分析。

Author: Msuenb

Date: 2023-02-16


java.lang.String类代表字符串。String 对象用于保存字符串,也就是一组字符序列。字符串是常量,它们的值在创建后不能更改。

String 的特点

  1. String 是 final 类,不能被其他的类继承

  2. String 类实现了 Comparable 接口,String 对象可以比较大小

  3. String 对象内部是用字符数组保存字符串内容的

    JDK9之前是 private final char value[] 数组,JDK9之后是 byte[] 数组

    "hello"等效于char[] value = {'h', 'e', 'l', 'l', 'o'}

  4. String 对象是不可变对象,一旦进行修改,就会产生新对象

    注意:

    • String 类的 char[] value 数组是 final 修饰的,说明 value 数组地址不可变,不是数组元素不可变
    • 由于 value 数组是 private 的,所以在 String 类外无法直接修改 value 数组的元素值(除非用反射)
    • String 类中的方法涉及到 value 数组长度变化,或修改元素值,都是用用新对象来表示修改后内容
    final char[] value = {'h', 'e', 'l', 'l', 'o'};
    // value = new char[5];    // value 的地址不可修改
    value[0] = 'H'; // 可以修改 value 元素值
    
    String str = "hello";
    str = "world";  
    // 不会修改 "hello", 会在池中创建一个新的String对象接受 "world"  str指向这个新对象 共会创建两个对象
    
  5. String 对象不可变,可以共享(节省内存)。Java 中把需要共享的字符串常量对象存放在常量池中。

    String s1 = "hello";
    String s2 = "hello";
    System.out.println(s1 == s2);   // true
    // 内存中只有一个 "hello" 对象被创建,同时被s1和s2共享
    

创建String对象

总的来说,String 对象的创建方式有两种:直接赋值 和 使用构造器,这两种方式的机制是不一样的

  • 直接赋值:String str1 = "hello";
    • 先从常量池中查看是否有 "hello" 数据空间,如果有,直接指向;如果没有,重新创建,然后指向。
    • str1 最终指向的是常量池的空间地址
  • 调用构造器:String str2 = new String("hello")
    • 先在堆中创建空间,里面维护了 char[] value属性。
    • 如果常量池中有 "hello" 数据空间,value 直接指向 "hello" 空间;如果没有,重新创建,然后指向。
    • str2 最终指向的是堆中的空间地址;value 才是指向常量池的空间地址

String 内存分析

针对下面两行代码分析 String 对象的创建过程和内存布局

String str1 = "hello";
String str2 = new String("hello");

String 内存布局:

String 对象创建过程:

  • String str1 = "hello";
    1. 先去查看常量池中是否有 "hello" 数据空间,没有,创建 "hello" 数据空间
    2. 将 "hello" 数据空间的地址返回给 String 对象引用 str
  • String str2 = new String("hello");
    3. 先在堆中开辟空间,里面维护了 value 属性,str2 指向这片空间
    4. 检查常量池中是否有 "hello" 数据空间,有,value 直接指向 "hello" 数据空间

哪些字符串对象地址放入字符串常量池:

需要共享的字符串地址记录到字符串常量池的table表中,不需要共享的字符串对象其地址值不需要记录到字符串常量池的table表中。
除了以下2种,其他的都不放入字符串常量池:
1. "..." 字符串字面量
2. 字符串对象.intern()的结果
 
其他:
1. 直接new
2. valueOf,copyValueOf等
3. 字符串对象拼接:concat拼接 以及 +左右两边出现  非字符串字面量拼接
4. toUpperCase,toLowerCase,substring,repalce等各种String方法得到的字符串
其实下面这些方式,本质都是新new的,其地址都是指向堆空间。

String对象的创建形式

String对象的创建方式有两种,使用其它形式生成String对象,像valueOf()toString(),它们在底层也是调用String的构造方法

  • 直接赋值

    String str = "hello";
    
  • 构造方法

    用于创建 String 对象的构造方法有很多,比较常用的有以下几个:

    1. public String() :其表示创建空字符序列
    2. String(String original):其表示创建一个与参数相同的字符序列;也即新创建的字符串是该参数字符串的副本。
    3. public String(char[] value) :通过当前参数中的字符数组来构造新的String。
    4. public String(byte[] bytes) :通过使用默认字符集解码当前参数中的字节数组来构造新的String。也可以指定字符集
    String str1 = new String();  // 创建一个空字符串
    String str2 = new String("hello");
    System.out.println(str1.equals(""));    // true
    
    char[] value = {'h', 'e', 'l', 'l', 'o'};	// 字符数组
    String str3 = new String(value);
    
    byte[] bytes = {104, 101, 108, 108, 111};	// 字节数组
    String str5 = new String(bytes);	// hello
    
  • valueOfcopyValueOf方法:

    1. static String copyValueOf(char[] data): 返回指定数组中表示该字符序列的 String

    2. static String valueOf(char[] data) : 返回指定数组中表示该字符序列的 String

    3. static String valueOf(xx value):xx支持各种数据类型,返回各种数据类型的value参数的字符串表示形式。

    char[] data = {'h','e','l','l','o','j','a','v','a'};
    String s1 = String
首页 上一页 1 2 3 4 下一页 尾页 1/4/4
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Redis数据结构实战演练,看看微博.. 下一篇委派模式——从SLF4J说起

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目