杰瑞科技汇

Java String 是引用类型,为何特殊?

是的,这个说法是完全正确的,在 Java 中,String 是一个引用类型(Reference Type)

Java String 是引用类型,为何特殊?-图1
(图片来源网络,侵删)

为了深入理解这一点,我们需要区分 Java 中的两种基本数据类型:

  1. 基本类型(Primitive Types):如 int, double, char, boolean 等,它们不是对象,直接存储值本身。
  2. 引用类型(Reference Types):如所有类(包括 String)、接口、数组等,它们存储的是指向对象在内存中实际位置的引用(地址),而不是对象本身。

String 作为引用类型的工作原理

当你声明一个 String 变量时,你实际上是在创建一个引用,这个引用可以指向一个 String 对象。

让我们通过一个例子来详细说明:

String str1 = "Hello";

这段代码在内存中发生了什么?

Java String 是引用类型,为何特殊?-图2
(图片来源网络,侵删)
  1. 字符串常量池:Java 会在一个特殊的内存区域叫做字符串常量池 中查找是否已经存在值为 "Hello" 的字符串对象。
  2. 创建或复用对象
    • 如果池中没有 "Hello",JVM 就会在池中创建一个新的 String 对象,内容为 "Hello"。
    • 如果池中已经存在,就直接复用这个已有的对象。
  3. 创建引用:变量 str1 被创建在栈内存 中,它存储的是指向堆内存(或字符串常量池,具体取决于JVM实现和Java版本)中那个 "Hello" 对象的内存地址

str1 本身并不包含 "Hello",它只包含了一个指向 "Hello" 对象的“指针”或“引用”。


引用类型的典型行为:多个引用指向同一个对象

这是引用类型最核心的特征,我们可以将多个变量指向同一个对象。

String str1 = "Hello";
String str2 = str1; // str2 也指向 str1 所指向的同一个对象

str1str2 都持有同一个 "Hello" 对象的引用。

一个常见的误区:修改字符串

Java String 是引用类型,为何特殊?-图3
(图片来源网络,侵删)

很多初学者会认为,既然 str1str2 指向同一个对象,那么修改其中一个,另一个也会改变,但这是错误的,因为 String 有一个非常重要的特性:不可变性

String str1 = "Hello";
String str2 = str1;
System.out.println("str1: " + str1); // 输出: str1: Hello
System.out.println("str2: " + str2); // 输出: str2: Hello
// 尝试修改 str1
str1 = str1 + " World"; 
System.out.println("str1 修改后: " + str1); // 输出: str1 修改后: Hello World
System.out.println("str2 的值: " + str2);     // 输出: str2 的值: Hello

为什么 str2 没有变?

  1. str1 = str1 + " World"; 这行代码看起来像是修改了 str1 指向的对象,但实际上不是。
  2. 由于 String 不可变,JVM 不能修改原有的 "Hello" 对象。
  3. JVM 会创建一个全新的 String 对象,内容为 "Hello World"。
  4. 变量 str1 的引用被更新为指向这个新创建的 "Hello World" 对象。
  5. str2 的引用没有改变,它依然指向原来的那个 "Hello" 对象。

这个例子恰恰证明了 String 是引用类型:我们操作的是引用(改变它指向了谁),而不是直接操作对象内容(因为内容不能被修改)。


Stringnew 关键字

使用字面量()创建 String 和使用 new 关键字创建 String 在内存管理上有细微差别。

// 方式一:使用字面量 (推荐)
String s1 = "Java";
String s2 = "Java"; // s1 和 s2 指向常量池中的同一个对象
// 方式二:使用 new 关键字
String s3 = new String("Java"); // 总是在堆内存中创建一个新对象
String s4 = new String("Java"); // s3 和 s4 指向堆内存中两个不同的对象
System.out.println(s1 == s2);      // true (比较引用地址,指向同一个常量池对象)
System.out.println(s3 == s4);      // false (比较引用地址,指向堆中两个不同对象)
System.out.println(s1 == s3);      // false (一个指向常量池,一个指向堆)
  • 对于引用类型, 比较的是两个引用是否指向同一个对象(即内存地址是否相同)。
  • .equals()String 类重写了 equals() 方法,它比较的是两个 String 对象的内容是否相同,而不是地址。

特性 说明
类型 String 是 Java 中的引用类型,属于 java.lang 包下的一个最终类。
存储 String 变量存储的是对象的引用(内存地址),而不是字符串本身。
内存位置 String 对象通常存储在堆内存中,通过字面量创建的字符串会先被放入字符串常量池以提高性能和节省内存。
不可变性 String 对象是不可变的,任何看似修改字符串的操作(如 连接)实际上都会创建一个新的 String 对象。
比较 - :比较两个引用是否指向同一个对象。
- .equals():比较两个字符串的内容是否相同。

"Java string是引用类型" 这个说法是 Java 语言的核心概念之一,理解它对于掌握 Java 的内存管理和对象行为至关重要。

分享:
扫描分享到社交APP
上一篇
下一篇