杰瑞科技汇

Java基本数据类型为何String不是?

数据类型

在编程中,数据类型是用来声明不同类型的变量,它告诉编译器这个变量可以存储什么样的数据,以及可以对它执行哪些操作,Java 的数据类型主要分为两大类:

Java基本数据类型为何String不是?-图1
(图片来源网络,侵删)
  1. 基本数据类型
  2. 引用数据类型

基本数据类型

基本数据类型是 Java 语言内置的、最简单的数据类型,它们不是对象,没有方法,直接存储在内存的 中,速度非常快,Java 一共定义了 8 种基本数据类型。

我们可以将它们分为四类:整数、浮点数、字符、布尔

整数类型

用于存储没有小数部分的数字。

类型 大小 (字节) 范围 默认值 备注
byte 1 -128 到 127 0 在处理字节数据(如文件、网络传输)时很有用。
short 2 -32,768 到 32,767 0 较少使用,通常用于特定场景。
int 4 -2,147,483,648 到 2,147,483,647 0 最常用的整数类型,默认的整数字面量。
long 8 -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 0L 用于表示非常大的整数。字面量后必须加 'L' 或 'l'

示例代码:

Java基本数据类型为何String不是?-图2
(图片来源网络,侵删)
int age = 30; // int 是最常用的
long population = 7800000000L; // 注意 L 后缀,否则会编译错误
byte smallNumber = 100;

浮点类型

用于存储带有小数部分的数字(即实数)。

类型 大小 (字节) 精度 默认值 备注
float 4 单精度 (约 7 位有效数字) 0f 字面量后必须加 'F' 或 'f',不推荐用于需要高精度的财务计算。
double 8 双精度 (约 15 位有效数字) 0d 最常用的浮点类型,默认的浮点字面量。

示例代码:

double price = 19.99; // double 是最常用的
float pi = 3.14f;    // 注意 f 后缀

字符类型

用于存储单个字符。

类型 大小 (字节) 范围 默认值 备注
char 2 \u0000\uffff (Unicode 字符) '\u0000' 使用单引号括起来,本质是一个 16 位的无符号整数,表示 Unicode 编码。

示例代码:

Java基本数据类型为何String不是?-图3
(图片来源网络,侵删)
char grade = 'A';
char chineseChar = '中'; // Java 内置对 Unicode 的支持
char escapeChar = '\n';  // 转义字符,代表换行

布尔类型

用于表示逻辑上的“真”或“假”。

类型 大小 (字节) 范围 默认值 备注
boolean 1 (理论值,JVM 实现可能不同) truefalse false 只能取这两个值,用于逻辑判断。

示例代码:

boolean isJavaFun = true;
boolean isLearning = false;

String:特殊的引用数据类型

String 在 Java 中是一个非常特殊的存在,虽然它是一个引用数据类型(因为它是一个类),但它的使用方式却和基本数据类型非常相似,这是 Java 为了方便程序员而做的特殊设计。

String 的本质

  • String 是一个预定义在 java.lang 包中的 final 类,这意味着你不能继承 String 类。
  • 不可变性:这是 String 最核心、最重要的特性,一旦一个 String 对象被创建,它的内容就不能被改变,任何对字符串的修改操作(如拼接、替换)实际上都是创建了一个新的 String 对象,而原始对象保持不变。

String 的创建

有两种主要的创建方式,但它们有本质区别。

使用字面量(推荐)

当代码中写一个用双引号括起来的字符串时,JVM 会在字符串常量池中检查是否已经存在该字符串,如果存在,就直接引用;如果不存在,就创建一个新的并放入池中。

String str1 = "Hello";
String str2 = "Hello"; // str1 和 str2 引用的是字符串常量池中同一个 "Hello" 对象
System.out.println(str1 == str2); // 输出 true,因为它们指向同一个内存地址

使用 new 关键字

使用 new 关键字会强制在堆内存中创建一个新的 String 对象,即使内容相同,也不会去检查字符串常量池。

String str3 = new String("Hello");
String str4 = new String("Hello"); // str3 和 str4 指向堆中两个不同的对象
System.out.println(str3 == str4); // 输出 false,因为它们指向不同的内存地址

String 的不可变性示例

String original = "Java";
System.out.println("原始字符串: " + original); // Java
// concat() 方法看起来修改了字符串,但实际上返回了一个新对象
String modified = original.concat(" is awesome!");
System.out.println("修改后 original: " + original); // 输出 "Java" (原始字符串未变)
System.out.println("新字符串 modified: " + modified); // 输出 "Java is awesome!"

为什么 String 要设计成不可变?

  1. 线程安全不可变,String 对象在多线程环境下是天然安全的,无需额外的同步机制。
  2. 性能优化:字符串常量池的机制可以避免在内存中创建大量重复的字符串,节省了内存空间,这也是为什么推荐使用字面量创建 String
  3. 安全:在处理文件路径、网络地址、数据库 URL 等敏感信息时,不可变性可以防止被意外或恶意修改。
  4. 作为 HashMap 的键:因为 StringhashCode() 在创建后就不会改变,所以它非常适合作为 HashMapHashtable 的键。

基本数据类型 vs. String

特性 基本数据类型 String
类型 内置的、非面向对象的数据类型 一个 java.lang 包中的类(引用数据类型)
存储位置 (字符串常量池是堆中的一块特殊区域)
默认值 有(如 int0booleanfalse null
方法 没有 有大量内置方法(如 length(), substring(), indexOf() 等)
比较 使用 比较值(内存地址也相同) 使用 比较内存地址,使用 .equals() 比较内容
可变性 不可变 不可变

.equals() 的重要区别

这是面试和开发中经常遇到的知识点。

    • 对于基本数据类型:比较的是是否相等。
    • 对于引用数据类型(如 String):比较的是内存地址(即是否指向同一个对象)是否相等。
  • .equals()

    • 对于 String 类:比较的是是否相等。
    • 对于其他引用类型:默认行为也是比较内存地址(继承自 Object 类),但很多类会重写这个方法来比较内容。

示例:

int a = 10;
int b = 10;
System.out.println(a == b); // true, 值相等
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
System.out.println(s1 == s2); // true, 指向常量池中同一个对象
System.out.println(s1 == s3); // false, s1 在常量池,s3 在堆中,是不同对象
System.out.println(s1.equals(s3)); // true, equals() 方法比较的是内容 "hello" 是否相等

  1. Java 有 8 种基本数据类型byte, short, int, long, float, double, char, boolean,它们是构建程序逻辑的基础,直接存储在栈中,速度快。
  2. String 是一个特殊的引用类型,它虽然是一个类,但使用起来像基本类型。
  3. String 的核心特性是不可变性,这带来了线程安全、性能优化等诸多好处。
  4. 创建 String 有两种方式:字面量(推荐,利用常量池)和 new(强制在堆中创建新对象)。
  5. 比较 String 时要特别注意: 比较的是地址,.equals() 比较的是内容,在绝大多数情况下,我们都应该使用 .equals() 来判断两个字符串内容是否相同。

理解这些概念对于编写高效、健壮的 Java 代码至关重要。

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