Java中的数据类型
Java 数据类型详解目录
[*]数据类型分类
[*]基本数据类型
[*]引用类型
[*]基本类型 vs 引用类型
[*]包装类
[*]String 详解
[*]字符串常量池
[*]内存布局
[*]对象生命周期
[*]常见问题
数据类型分类
Java 数据类型
├── 基本类型(8种)
│ ├── 整数类型:byte, short, int, long
│ ├── 浮点类型:float, double
│ ├── 字符类型:char
│ └── 布尔类型:boolean
└── 引用类型
├── 类(如 String)
├── 接口
└── 数组基本数据类型
整数类型
类型位数范围默认值示例byte8位-128 ~ 1270byte b = 100;short16位-32,768 ~ 32,7670short s = 10000;int32位-21亿 ~ 21亿0int i = 100000;long64位极大0Llong l = 100000L;bytea = 127; // ✅ 最大值
// byte b = 128;// ❌ 超出范围
int c = 100;
longd = 100000L; // long 需加 L 或 l
longe = 10000000000L; // ✅ 超出int范围必须加L
// longf = 10000000000; // ❌ 编译错误,超出 int 范围浮点类型
类型位数精度默认值示例float32位单精度(7位有效数字)0.0ffloat f = 3.14f;double64位双精度(15位有效数字)0.0double d = 3.14;double a = 3.14; // 默认是 double
// float b = 3.14;// ❌ 编译错误
floatc = 3.14f; // ✅字符类型
类型位数说明默认值示例char16位单个 Unicode 字符\u0000char 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 只能存单个字符布尔类型
类型取值默认值示例booleantrue, falsefalseboolean flag = true;boolean a = true;
boolean b = false;引用类型
什么是引用类型
引用类型存储的是对象的地址(引用),对象本身存储在堆中。
常见引用类型
类型说明示例String字符串类String s = "hello";数组数组int[] arr = {1, 2, 3};接口接口类型List list;自定义类用户定义的类Person p = new Person();基本类型 vs 引用类型
对比维度基本类型引用类型(如 String)存储位置栈中,直接存值栈存引用,堆存对象大小固定(如 int 4字节)不固定默认值0/false/\u0000null比较== 比较值== 比较地址,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 String("hello");
System.out.println(s1 == s2); // false(不同地址)
System.out.println(s1.equals(s2)); // true(内容相同)包装类
每个基本类型都有对应的包装类:
基本类型包装类说明byteByteshortShortintIntegerlongLongfloatFloatdoubleDoublecharCharacterbooleanBooleanint a = 10; // 基本类型
Integer b = 10; // 包装类
Integer c = Integer.valueOf(10); // 显式创建
// 自动装箱/拆箱
Integer d = a; // 自动装箱
int e = d; // 自动拆箱String 详解
String 是什么?
String 是类,不是基本类型,是不可变的引用类型。
String 的不可变性
String a = "hello";
String b = a; // a 和 b 指向同一对象
a = "world"; // a 指向新对象
System.out.println(b); // 输出: hello(b 不变)
System.out.println(a == b); // false(已不是同一对象)内存变化:
修改前:
a ──→ ["hello"]
↑
b
修改后:
a ──→ ["world"]← 新对象
b ──→ ["hello"]← 原对象不变为什么 String 不可变?
// String 简化版源码
public final class String {
private final char value[];// final,不能修改
// 所有修改操作都返回新 String
public String substring(int beginIndex) {
return new String(value, beginIndex, count);
}
}原因说明不可变String 对象一旦创建,内容不能改finalString 类内部用 final 修饰字符数组安全多线程环境下,无需加锁就能安全共享String vs 可变对象
// String - 不可变
String a = "hello";
String b = a;
a = "world";
System.out.println(b);// hello(不变)
// StringBuilder - 可变
StringBuilder sb1 = new StringBuilder("hello");
StringBuilder sb2 = sb1;
sb1.append(" world");
System.out.println(sb2);// hello world(变了!)字符串常量池
什么是字符串常量池
┌─────────────────────────────────────────────────────┐
│ 字符串常量池 │
│(JVM 堆内存中的一块特殊区域,专门存储字符串字面量)│
│ │
│ "hello" │
│ "world" │
│ "java" │
└─────────────────────────────────────────────────────┘字面量 vs new
方式写法存储位置是否复用隐式(字面量)String s = "hello";字符串常量池✅ 复用显式(new)String s = new String("hello");堆内存(新对象)❌ 新对象动态创建scanner.nextLine()堆内存(新对象)❌ 新对象字面量(隐式赋值)
String a = "hello";
String b = "hello";流程:
[*]JVM 检查常量池中是否有 "hello"
[*]有 → 直接引用(复用)
[*]无 → 在常量池创建 "hello",然后引用
常量池:
┌─────────┐
│ "hello" │ ← a ─┐
└─────────┘ │
│ 两者指向同一对象
├─ bSystem.out.println(a == b);// true(同一对象)new(显式赋值)
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(值相同)scanner 输入
String c = scanner.nextLine(); // 输入: hello
String d = scanner.nextLine(); // 输入: hello
System.out.println(c == d); // false(每次新对象)内存布局
Java 版本差异
版本常量池位置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" │ ← 在常量池 │
│ └─────────┘ │
│ │
└───────────────────────────────────────────────────┘new String("xxx") 的步骤
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)
GC = Garbage Collection,Java 自动内存管理机制。
GC 工作原理:
1. 定期扫描堆内存
2. 找出没有被引用的对象
3. 回收内存不同区域的回收策略
类型生命周期回收方式字面量(常量池)程序运行期间一般不回收动态对象(堆)到无引用时GC 回收基础类型(栈)作用域内自动销毁String a = "hello";// 常量池,程序运行期间存在
String b = scanner.nextLine();// 堆对象
b = null;// 失去引用,等待 GCintern() 方法
将字符串内容放入常量池。
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 == s4); // true(都是常量池)常见问题
Q1: \u0000 是什么?
\u0000 是 Unicode 字符的转义表示,表示 Unicode 值为 0 的字符。
方面说明Unicode 值0名称null 字符 / 空字符可见性不可见(控制字符)Java 中char 的默认值char c = '\u0000'; // null 字符
char d = 0; // 等价写法
System.out.println(c == d); // true
System.out.println((int)c); // 输出: 0Q2: String 引用相同但值不同?
对于 String,不可能。
String a = "hello";
String b = a;
a = "world";
System.out.println(b);// hello(b 不变)核心原因: String 是不可变的,引用相同则值必相同。
Q3: scanner.nextLine() 返回什么?
永远返回 String,无论输入什么。
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();// 输入 27 → "27"(字符串)
// 如果要转整数
int num = Integer.parseInt(input);// "27" → 27方法输入 27返回类型nextLine()"27"StringnextInt()27intnextDouble()27.0doubleQ4: 常量池在堆上吗?
是的,现代 Java(7+)中,字符串常量池在堆上。
但常量池是堆中特殊管理的区域,与普通堆对象有区别:
对比维度常量池对象普通堆对象位置堆(特殊区域)堆(普通区域)创建方式字面量、intern()new String()去重✅ 自动去重❌ 不去重生命周期一般长期存在无引用后 GC 回收总结速查表
基本类型速查
类型位数范围默认值byte8-128 ~ 1270short16±3.2万0int32±21亿0long64极大0Lfloat32单精度0.0fdouble64双精度0.0char16单字符\u0000boolean1true/falsefalseString 对比速查
操作结果String a = "hello";
String b = "hello";a == b → trueString c = new String("hello");
String d = new String("hello");c == d → falsea == cfalse(常量池 vs 堆)a.equals(c)true(值相同)记忆口诀
基础类型 引用类型
↓ ↓
栈 栈 + 堆
直接值 引用+对象
字面量 scanner输入
↓ ↓
常量池 堆新对象
可复用 不复用
String→ 引用同,值必同(不可变)
StringBuilder → 引用同,值随变(可变)注:同步发布于金蝶开发者社区:Java数据类型
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 这个有用。 鼓励转贴优秀软件安全工具和文档! yyds。多谢分享 前排留名,哈哈哈 很好很强大我过来先占个楼 待编辑 鼓励转贴优秀软件安全工具和文档! 这个有用。 感谢分享,下载保存了,貌似很强大 收藏一下 不知道什么时候能用到 懂技术并乐意极积无私分享的人越来越少。珍惜 感谢发布原创作品,程序园因你更精彩 前排留名,哈哈哈 喜欢鼓捣这些软件,现在用得少,谢谢分享! 很好很强大我过来先占个楼 待编辑 这个好,看起来很实用 感谢分享 这个有用。
页:
[1]