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

- 基本数据类型
- 引用数据类型
基本数据类型
基本数据类型是 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'。 |
示例代码:

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 编码。 |
示例代码:

char grade = 'A'; char chineseChar = '中'; // Java 内置对 Unicode 的支持 char escapeChar = '\n'; // 转义字符,代表换行
布尔类型
用于表示逻辑上的“真”或“假”。
| 类型 | 大小 (字节) | 范围 | 默认值 | 备注 |
|---|---|---|---|---|
boolean |
1 (理论值,JVM 实现可能不同) | true 或 false |
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 要设计成不可变?
- 线程安全不可变,
String对象在多线程环境下是天然安全的,无需额外的同步机制。 - 性能优化:字符串常量池的机制可以避免在内存中创建大量重复的字符串,节省了内存空间,这也是为什么推荐使用字面量创建
String。 - 安全:在处理文件路径、网络地址、数据库 URL 等敏感信息时,不可变性可以防止被意外或恶意修改。
- 作为
HashMap的键:因为String的hashCode()在创建后就不会改变,所以它非常适合作为HashMap或Hashtable的键。
基本数据类型 vs. String
| 特性 | 基本数据类型 | String |
|---|---|---|
| 类型 | 内置的、非面向对象的数据类型 | 一个 java.lang 包中的类(引用数据类型) |
| 存储位置 | 栈 | 堆(字符串常量池是堆中的一块特殊区域) |
| 默认值 | 有(如 int 是 0,boolean 是 false) |
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" 是否相等
- Java 有 8 种基本数据类型:
byte,short,int,long,float,double,char,boolean,它们是构建程序逻辑的基础,直接存储在栈中,速度快。 String是一个特殊的引用类型,它虽然是一个类,但使用起来像基本类型。String的核心特性是不可变性,这带来了线程安全、性能优化等诸多好处。- 创建
String有两种方式:字面量(推荐,利用常量池)和new(强制在堆中创建新对象)。 - 比较
String时要特别注意: 比较的是地址,.equals()比较的是内容,在绝大多数情况下,我们都应该使用.equals()来判断两个字符串内容是否相同。
理解这些概念对于编写高效、健壮的 Java 代码至关重要。
