首页 > 应用开发 > Java > Java中的数据类型
Java 数据类型 ├── 基本类型(8种) │ ├── 整数类型:byte, short, int, long│ ├── 浮点类型:float, double│ ├── 字符类型:char│ └── 布尔类型:boolean└── 引用类型 ├── 类(如 String) ├── 接口 └── 数组
| 类型 | 位数 | 范围 | 默认值 | 示例 |
|---|---|---|---|---|
byte |
8位 | -128 ~ 127 | 0 |
byte b = 100; |
short |
16位 | -32,768 ~ 32,767 | 0 |
short s = 10000; |
int |
32位 | -21亿 ~ 21亿 | 0 |
int i = 100000; |
long |
64位 | 极大 | 0L |
long l = 100000L; |
byte a = 127; // ✅ 最大值// byte b = 128; // ❌ 超出范围int c = 100;long d = 100000L; // long 需加 L 或 llong e = 10000000000L; // ✅ 超出int范围必须加L// long f = 10000000000; // ❌ 编译错误,超出 int 范围
| 类型 | 位数 | 精度 | 默认值 | 示例 |
|---|---|---|---|---|
float |
32位 | 单精度(7位有效数字) | 0.0f |
float f = 3.14f; |
double |
64位 | 双精度(15位有效数字) | 0.0 |
double d = 3.14; |
double a = 3.14; // 默认是 double// float b = 3.14; // ❌ 编译错误float c = 3.14f; // ✅
| 类型 | 位数 | 说明 | 默认值 | 示例 |
|---|---|---|---|---|
char |
16位 | 单个 Unicode 字符 | \u0000 |
char c = 'A'; |
char a = 'A'; // 字符char b = '中'; // 中文char c = 65; // 数字对应字符 'A'char d = '\u0041'; // Unicode 转义,'A'char e = '\u0000'; // null 字符,char 的默认值// char f = 'AB'; // ❌ char 只能存单个字符
| 类型 | 取值 | 默认值 | 示例 |
|---|---|---|---|
boolean |
true, false | false |
boolean flag = true; |
boolean a = true;boolean b = false;
引用类型存储的是对象的地址(引用),对象本身存储在堆中。
| 类型 | 说明 | 示例 |
|---|---|---|
| String | 字符串类 |
String s = "hello"; |
| 数组 | 数组 |
int[] arr = {1, 2, 3}; |
| 接口 | 接口类型 |
List<String> list; |
| 自定义类 | 用户定义的类 |
Person p = new Person(); |
| 对比维度 | 基本类型 | 引用类型(如 String) |
|---|---|---|
| 存储位置 | 栈中,直接存值 | 栈存引用,堆存对象 |
| 大小 | 固定(如 int 4字节) | 不固定 |
| 默认值 | 0/false/\u0000 | null |
| 比较 |
== 比较值 |
== 比较地址,
equals() 比较内容 |
基本类型: 栈 ┌─────────┐ │ int a │ = 10└─────────┘ 直接存值 引用类型: 栈 堆 ┌─────────┐ ┌─────────┐ │String s │ ────────→│ "hello" │ └─────────┘ └─────────┘ 引用变量 实际对象
// 基本类型int a = 10;int b = 10;
System.out.println(a == b); // true(比较值)// 引用类型String s1 = new String("hello");String s2 = new yccgc.cn String("hello");
System.out.println(s1 == s2); // false(不同地址)System.out.println(s1.equals(s2)); // true(内容相同)
每个基本类型都有对应的包装类:
| 基本类型 | 包装类 | 说明 |
|---|---|---|
byte |
Byte |
|
short |
Short |
|
int |
Integer |
|
long |
Long |
|
float |
Float |
|
double |
Double |
|
char |
Character |
|
boolean |
Boolean |
|
int a = 10; // 基本类型Integer b = 10; // 包装类Integer c = Integer.valueOf(10); // 显式创建// 自动装箱/拆箱Integer d = a; // 自动装箱int e = d; // 自动拆箱
String 是类,不是基本类型,是不可变的引用类型。
String a = "hello";String b = a; // a 和 b 指向同一对象a = "world"; // a 指向新对象System.out.println(b); // 输出: hello(b 不变) www.yccgc.cn System.out.println(a == b); // false(已不是同一对象)
内存变化: 修改前:a ──→ ["hello"] ↑ b修改后:a ──→ ["world"] ← 新对象b ──→ ["hello"] ← 原对象不变
// String 简化版源码public final class String { private final char value[]; // final,不能修改
// 所有修改操作都返回新 String
public String substring(int beginIndex) { return new String(value, beginIndex, count);
}
}
| 原因 | 说明 |
|---|---|
| 不可变 | String 对象一旦创建,内容不能改 |
| final | String 类内部用 final 修饰字符数组 |
| 安全 | 多线程环境下,无需加锁就能安全共享 |
// String - 不可变String a = "hello";String b = a;
a = "world";
System.out.println(b); // hello(不变)// StringBuilder - 可变StringBuilder sb1 = new StringBuilder("hello");String wap.yccgc.cn Builder sb2 = sb1;
sb1.append(" world");
System.out.println(sb2); // hello world(变了!)
┌─────────────────────────────────────────────────────┐ │ 字符串常量池 │ │ (JVM 堆内存中的一块特殊区域,专门存储字符串字面量) │ │ │ │ "hello" │ │ "world" │ │ "java" │ └─────────────────────────────────────────────────────┘
| 方式 | 写法 | 存储位置 | 是否复用 |
|---|---|---|---|
| 隐式(字面量) |
String s = "hello"; |
字符串常量池 | ✅ 复用 |
| 显式(new) |
String s = new String("hello"); |
堆内存(新对象) | ❌ 新对象 |
| 动态创建 |
scanner.nextLine() |
堆内存(新对象) | ❌ 新对象 |
String a = "hello";String b = "hello";
流程:
"hello""hello",然后引用常量池: ┌─────────┐ │ "hello" │ ← a ─┐ └─────────┘ │ │ 两者指向同一对象 ├─ b
System.out.println(a == b); // true(同一对象)
String c = new String("hello");String d = new String("hello");
流程:
"hello"常量池: 堆内存: ┌─────────┐ ┌─────────┐ │ "hello" │ ───→ │ "hello" │ ← c └─────────┘ └─────────┘ ┌─────────┐ │ "hello" │ ← d └─────────┘
System.out.println(c == d); // false(不同对象)System.out.println(c == a); // false(c 在堆,a 在常量池)System.out.println(c.equals(a)); // true(值相同)
String c = scanner.nextLine(); // 输入: helloString d = scanner.nextLine(); // 输入: helloSystem.out.println(c == d); // false(每次新对象)
| 版本 | 常量池位置 |
|---|---|
| Java 6 及之前 | 方法区(代 PermGen) |
| Java 7+ | 堆 |
| Java 8+ | 堆(方法区改为元空间 Metaspace) |
现代 Java(7+):字符串常量池在堆上。
String s1 = "first";String s2 = new String("second");
栈:
┌─────────┐ ┌─────────┐
│ s1 │ │ s2 │
└─────────┘ └─────────┘
↓ 引用 ↓ 引用
堆(都在堆上):
┌───────────────────────────────────────────────────┐
│ │
│ 常量池区域: 普通堆区域: │
│ ┌─────────┐ ┌─────────────────────┐ │
│ │ "first" │ │ String对象 │ │
│ │"second" │ │ value → "second" │ │
│ └─────────┘ └─────────────────────┘ │
│ ↓ │
│ ┌─────────┐ │
│ │"second" │ ← 在常量池 │
│ └─────────┘ │
│ │
└───────────────────────────────────────────────────┘
1. 先处理 "xxx" 字面量 → 检查常量池有没有 "xxx" → 没有 → 在常量池创建 "xxx" → 有 → 复用2. 再执行 new String() → 在普通堆创建新对象 → 对象内部引用常量池的 "xxx"
String s = new String("second");// 等价于:String literal = "second"; // 先处理字面量,进常量池String s = new String(literal); // 再创建堆对象
┌─────────────────────────────────────────────────────────┐ │ 对象一生 │ ├─────────────────────────────────────────────────────────┤ │ │ │ 1. 创建 → new String() / scanner.nextLine() │ │ ↓ │ │ 2. 使用 → 被变量引用,可以访问 │ │ ↓ │ │ 3. 失去引用 → 变量指向其他对象或离开作用域 │ │ ↓ │ │ 4. 可回收 → 等待 GC 清理 │ │ ↓ │ │ 5. 回收 → GC 自动回收内存 │ │ │ └─────────────────────────────────────────────────────────┘
String s1 = scanner.nextLine(); // 创建对象s1 = scanner.nextLine(); // s1 指向新对象,原对象可被回收
GC = Garbage Collection,Java 自动内存管理机制。
GC 工作原理:1. 定期扫描堆内存2. 找出没有被引用的对象3. 回收内存
| 类型 | 生命周期 | 回收方式 |
|---|---|---|
| 字面量(常量池) | 程序运行期间 | 一般不回收 |
| 动态对象(堆) | 到无引用时 | GC 回收 |
| 基础类型(栈) | 作用域内 | 自动销毁 |
String a = "hello"; // 常量池,程序运行期间存在String b = scanner.nextLine(); // 堆对象b = null; // 失去引用,等待 GC
将字符串内容放入常量池。
String s = new String("aaa");
s.intern(); // 将 "aaa" 内容放入常量池(如果还没)
String s1 = new String("aaa");String s2 = new String("aaa");String s3 = "aaa"; // 字面量,常量池String s4 = s1.intern(); // 返回常量池中的引用System.out.println(s1 == s2); // false(堆对象,不同)System.out.println(s1 == s3); // false(堆 vs 常量池)System.out.println(s3 m.yccgc.cn == s4); // true(都是常量池)
\u0000 是 Unicode 字符的转义表示,表示 Unicode 值为 0 的字符。
| 方面 | 说明 |
|---|---|
| Unicode 值 | 0 |
| 名称 | null 字符 / 空字符 |
| 可见性 | 不可见(控制字符) |
| Java 中 | char 的默认值 |
char c = '\u0000'; // null 字符char d = 0; // 等价写法System.out.println(c == d); // trueSystem.out.println((int)c); // 输出: 0
对于 String,不可能。
String a = "hello";String b = a; a = "world"; System.out.println(b); // hello(b 不变)
核心原因: String 是不可变的,引用相同则值必相同。
永远返回 String,无论输入什么。
Scanner scanner = new Scanner(System.in);String input = scanner.nextLine(); // 输入 27 → "27"(字符串)// 如果要转整数int num = Integer.parseInt(input www.tiyu.gov.cn.yccgc.cn ); // "27" → 27
| 方法 | 输入 27 | 返回类型 |
|---|---|---|
nextLine() |
"27" |
String |
nextInt() |
27 |
int |
nextDouble() |
27.0 |
double |
是的,现代 Java(7+)中,字符串常量池在堆上。
但常量池是堆中特殊管理的区域,与普通堆对象有区别:
| 对比维度 | 常量池对象 | 普通堆对象 |
|---|---|---|
| 位置 | 堆(特殊区域) | 堆(普通区域) |
| 创建方式 | 字面量、intern() | new String() |
| 去重 | ✅ 自动去重 | ❌ 不去重 |
| 生命周期 | 一般长期存在 | 无引用后 GC 回收 |
| 类型 | 位数 | 范围 | 默认值 |
|---|---|---|---|
byte |
8 | -128 ~ 127 | 0 |
short |
16 | ±3.2万 | 0 |
int |
32 | ±21亿 | 0 |
long |
64 | 极大 | 0L |
float |
32 | 单精度 | 0.0f |
double |
64 | 双精度 | 0.0 |
char |
16 | 单字符 | \u0000 |
boolean |
1 | true/false | false |
| 操作 | 结果 |
|---|---|
String a = "hello";
String b = "hello"; |
a == b →
true |
String c = new String("hello");
String d = new String("hello"); |
c == d →
false |
a == c |
false(常量池 vs 堆) |
a.equals(c) |
true(值相同) |
基础类型 引用类型 ↓ ↓ 栈 栈 + 堆 直接值 引用+对象字面量 scanner输入 ↓ ↓ 常量池 堆新对象 可复用 不复用String → 引用同,值必同(不可变) StringBuilder → 引用同,值随变(可变)
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70048949/viewspace-3109691/ ,如需转载,请注明出处,否则将追究法律责任。