
Java中的数据类型有哪些?分为哪两大类? (考点:Java数据类型及其分类) 【简单】

还有这个Integer Integer是int 的引用数据类型,
在数据库开发中,绝大多数情况下必须用 Integer 而不是 int,核心原因就三个字:"怕没填" (也就是能处理 null)。
与C++的对比与助记
1. 核心思想:Java 是"强迫症",C++ 是"自由派"
在 C++ 里,数据类型的大小往往看操作系统的脸色(比如 int 在 16 位机和 32 位机上大小不一样)。而且 C++ 有各种 unsigned(无符号),还有满天飞的指针。
但 Java 的设计理念是 "Write Once, Run Anywhere(一次编写,到处运行)" 。
为了实现这个吹过的牛,Java 变成了一个"极度自律的强迫症":它把所有基本数据类型的大小全部钉死了,不论在什么机器上,永远一样大! 并且,它没收了你直接操作内存的权利(干掉了显式指针)。
2. 用 C++ 助记 Java 的"八大基本类型"
我们把这 8 种类型分成四大家族,对比 C++ 来记:
🎸 第一家族:整数型(整整齐齐,绝无 unsigned)
- Java 只有有符号数 ,没有 C++ 里那种
unsigned int。 byte(8位) :这是 Java 特有的!在 C++ 里你通常得用signed char或者int8_t来代替。它专门用来处理底层文件流或网络传输,非常省空间。short(16位) :对应 C++ 的short。int(32位):永远是 32 位!不再像 C++ 那样摇摆不定。long(64位) :在 Java 里不管什么系统,long就是 64 位。记得赋值时屁股后面要加个L(如100L)。
🌊 第二家族:浮点型(几乎一样)
float(32位) 和double(64位) :这俩跟 C++ 几乎一模一样。唯一的考点是:Java 也是个严格的家伙,写float f = 3.14;会报错!因为带小数点的字面量默认是double,大塞小塞不进去,必须写成3.14f。
🎭 第三家族:字符型(格局打开了)
- C++ 的
char:8位,通常装的是 ASCII 码,只能装英文字母和简单符号。 - Java 的
char:16位! Java 诞生得晚,格局大,直接用了 Unicode 编码。这意味着 Java 的一个char可以直接装下一个中文字符!比如char c = '牛';在 Java 里是完全合法的。
🚦 第四家族:布尔型(楚河汉界,极其死板)
- C++ 的
bool:很随便,0就是false,非0就是true。你可以写if(1)。 - Java 的
boolean:极其严格!它和整数彻底断绝关系 。不能拿0当false,也不能参与任何类型转换。你只能老老实实写if(true)或者if(flag == true)。
3. 用 C++ 助记 Java 的"引用数据类型"
你笔记里写了:类、接口、数组。
用 C++ 的话翻译极其简单:Java 的引用数据类型,本质上就是 C++ 里被阉割了运算功能、但极其安全的"指针"!
- 在 C++ 里,
int* p是个指针,它里面存的是个内存地址。 - 在 Java 里,你
new出来一个对象Student s = new Student();,这个变量s就叫"引用"。它里面存的也是对象在堆内存里的地址。你不能对s进行s++这种指针偏移运算,Java 会帮你自动管理这块内存(垃圾回收 GC)。
4. 运算时的"潜规则"(自动类型提升)
你笔记里有一句极其关键的话:"byte,short,char 参与运算时,会自动转换为 int 类型。"
费曼解说 :CPU 的寄存器通常是 32 位的。为了算得快,Java 规定,凡是比 int 小的家伙(byte, short, char),只要一做加减乘除,CPU 就会嫌它们太小,直接一把将它们拽大到 int 级别再算 。算完之后,结果也是个 int。
🎯 检验时刻:Java 基础防坑测试题
不看上面的笔记,尝试用直觉回答这 4 个问题。答对了,这段八股文你就彻底融会贯通了!
- 判断对错并解释 :在 Java 中,因为
if(a)这种写法更简洁,所以当我们声明了int a = 1;时,可以直接写if(a) { System.out.println("Hello"); }。(提示:想想 Java 的布尔型性格) - 找茬题 :我写了这行代码
float pi = 3.14;编译器为什么给我标红报错了?我该怎么改? - 计算推演题 :已知
byte b1 = 10; byte b2 = 20;,我接着写byte b3 = b1 + b2;,这行代码能编译通过吗?为什么?(核心考点:潜规则) - C++老司机翻车题 :在 C++ 里
char c = '中';很容易溢出报错,但在 Java 里char c = '中';却完全没问题。请用一句话解释原因。
回答:
1 错
-
float pi = 3.14f
-
能,编译的时候自动给byte 转换成int 类型,隐式转换小转大
-
java中char 16 位 ,C++中8位
3 回答错误了
因为会隐式转换,所以相加之后变成了int 类型 32位 ,byte 反而放不下了
怎么改才能跑通?
顺从它(大接大):int b3 = b1 + b2; (最推荐)
强转它(我按手印我负责):byte b3 = (byte)(b1 + b2); (告诉编译器:出了事我自己担着,强转!)
对于引用数据类型
类 接口 数组 哪里应用了引用
.
在 C++ 里,int* p 是个指针,它里面存的是个内存地址。
在 Java 里,你 new 出来一个对象 Student s = new Student();,这个变量 s 就叫"引用"。它里面存的也是对象在堆内存里的地址。你不能对 s 进行 s++ 这种指针偏移运算,Java 会帮你自动管理这块内存(垃圾回收 GC)。
类 接口 数组 就是都用到了引用是吧,java ,对于类,就是类 在对象实例化的时候,就是对象其实就是一种引用
数组名就是一个存着内存地址的引用(相当于 C++ 里的数组名退化成的指针)
大方向完全正确!特别是对数组的理解,你极其精准:数组名就是一个存着内存地址的引用(相当于 C++ 里的数组名退化成的指针)。
但是,关于「类和对象」的那句话,咱们得稍微纠正一个初学者极容易混淆的概念。你说"对象其实就是一种引用,给类起个新名字换个新地址",这里有点把图纸 、实体 和遥控器搞混了。
为了通俗易懂,咱们把这三个词掰开揉碎:类 (Class) 、对象 (Object) 、引用 (Reference)。
1. 核心比喻:图纸、电视机与遥控器
- 类 (Class) = 图纸 / 模具 。它只是写在硬盘里的一段代码,规定了长什么样,比如
class Student就是张图纸,它不占实际运行时的内存。 - 对象 (Object) = 按照图纸造出来的"电视机"实体 。当你使用
new Student()时,Java 会在宽敞的堆内存 (Heap) 里,真的划出一大块空间,把这台电视机造出来。 - 引用 (Reference) = 操控这台电视机的"遥控器" 。当你写
Student s = ...的时候,这个s就是引用。它很小,通常存在栈内存 (Stack) 里,里面只存了一串数字(比如0x7788),这个数字就是电视机在堆内存里的地址。
所以,完整的动作 Student s = new Student(); 其实是分三步走的:
new Student():在堆里造了一台真电视机(对象)。Student s:在栈里配了一个遥控器(引用变量)。=(赋值):把电视机的地址,录入到遥控器里。把它们连起来!
2. 用 C++ 翻译一遍,秒懂!
在 C++ 里,这行代码的等价物其实是:
Student* s = new Student();
new Student()同样是在堆(Heap)上分配了内存。Student* s是一个指针变量(在 Java 里叫引用)。- 如果你想调用方法,C++ 是用箭头
s->study(),而在 Java 里统一简化成了点s.study()。
所以,引用不是给类起了个新名字,引用是指向内存中那个实实在在的对象的"安全指针"。
3. 那"接口"是怎么用引用的呢?
接口其实玩的是**"多态"**(万能遥控器)。
比如有个接口叫 Flyable(会飞的),有个类叫 Bird 实现了它。
你可以这么写:
Flyable f = new Bird();
new Bird():在堆里造了一只真正的鸟(对象)。Flyable f:你手里拿的是一个只带有"飞行按键"的通用遥控器(接口引用)。- 不管内存里是一只鸟还是一架飞机,只要它能飞,你手里的这个
f遥控器(引用)就能存它的地址,并且按下f.fly()按钮让它起飞! - C++ 翻译:这就像是父类指针指向子类对象。
总结一下你的思路
- 类实例化 :
Student s = new Student();->s是引用,存了真 Student 对象的地址。 - 接口实现 :
Flyable f = new Bird();->f是引用,存了真 Bird 对象的地址。 - 数组 :
int[] arr = new int[5];->arr是引用,存了那一长溜 5 个格子的首地址。
发现没?只要你看到了 new 关键字,就说明在堆内存里造了真家伙,而等号左边接住它的那个变量,全都是引用(存地址的遥控器)!
"Java 传参到底是值传递,还是引用传递?"
第一:String 到底是基本类型还是引用类型?为什么不可变?
1. 结论抢答
String 百分之百是引用数据类型!
Java 的基本数据类型只有那固定的 8 种(byte, short, int, long, float, double, char, boolean)。String 首字母大写,它是一个正儿八经的类 (Class)。
2. 什么是"不可变" (Immutable)?(对比 C++)
在 C++ 里,std::string s = "abc";,你完全可以写 s[0] = 'z';,把它变成 "zbc"。C++ 的字符串是可以随意修改的。
但在 Java 里,String 对象一旦被造出来,就绝对不可能被改变!
如果你写了这样的代码:
java
String s = "Hello";
s = s + " World"; // 拼接字符串
表面上看 s 变成了 "Hello World",但底层真相是:
原来那个装有 "Hello" 的内存块根本没变 !Java 只是在堆内存里新建 了一个叫 "Hello World" 的新对象,然后把 s 这个遥控器,重新指向了新对象的地址。原来的 "Hello" 像个孤儿一样被留在了内存里(等待垃圾回收)。
3. 为什么它能做到不可变?(底层的秘密)
如果你翻开 Java String 类的源码,你会发现它极其"鸡贼":
- 底层的阵列被锁死了 :
String内部其实是用一个字符数组char[](JDK 9 之后变成了byte[]) 来存数据的。但这个数组被声明为private final。private代表你拿不到它,final代表它一旦赋值地址就不能换。 - 不给任何修改方法 :
String类没有提供任何类似setChar(index, 'a')的方法。 - 类被绝育了 :
String类被final修饰,意味着你不能写个子类去继承它、篡改它的行为。它就像一个全封闭的防弹玻璃盒。
4. 面试官追问:为什么要设计成不可变?
- 安全:数据库密码、网络地址经常用 String 传。如果能被悄悄修改,黑客就乐疯了。
- 线程安全:因为谁也改不了它,所以多线程随便怎么读都不用加锁,绝对安全。
- 终极原因:为了省内存(字符串常量池) 。因为不可变,Java 就可以在内存里建一个"缓存池"。如果你写
String a = "abc"; String b = "abc";,Java 不会造两个对象,而是让a和b这两个遥控器指向同一个"abc"。只有不可变,才敢这么共享!
第二局:世纪大坑------Java 到底是值传递,还是引用传递?
请死死记住这个标准答案:Java 只有值传递(Pass-by-Value),绝对没有引用传递!
很多有 C++ 基础的人会在这里拍桌子:"不对啊!我把一个对象传进函数里,修改了它的属性,外面的对象也变了啊,这难道不是引用传递?"
别急,我们上**"遥控器"**比喻!
1. 基本类型的传递:复印纸条
java
void change(int x) { x = 10; }
int a = 5;
change(a); // a 还是 5
这个好理解,a 是一张写着 5 的纸条。传参的时候,Java 复印 了一张纸条递进函数里。你在函数里把复印件改成 10,关外面的原件什么事?这叫值传递。
2. 对象的传递:配了一把新遥控器
java
class TV { String channel = "CCTV-1"; }
void changeTV(TV remote2) {
remote2.channel = "CCTV-5"; // 动作 A
remote2 = new TV(); // 动作 B
}
TV remote1 = new TV();
changeTV(remote1);
高能预警,开始推演:
- 外面造了一台真电视,
remote1(遥控器1号)存了它的地址(比如0x111)。 - 调用函数
changeTV(remote1)。注意!Java 这里做的依然是值传递 !传递的是什么"值"?传递的是遥控器里的那串地址数字! - 也就是说,Java 在函数内部,克隆了一把一模一样的新遥控器
remote2,里面也存着0x111。 - 动作 A :你用
remote2按下了换台键(remote2.channel = "CCTV-5")。因为两个遥控器对准的是同一台电视,所以外面的电视确实换台了!(这就是让人误以为是引用传递的幻觉来源)。 - 动作 B(见证奇迹的时刻) :你在函数里写
remote2 = new TV()。这意味着,你在函数里造了一台新电视(地址0x222),并把函数里的那把新遥控器remote2对准了新电视。 - 结果 :外面的
remote1依然死死地指向原来的旧电视(0x111)。它根本没有被改变!
3. C++ 老司机的顿悟时刻
如果你用 C++ 翻译 Java 的对象传参,它完全等于 C++ 里的传指针(传值) ,而不是传引用(&)!
cpp
// Java 的行为完全等价于下面这段 C++ 代码:
void changeTV(TV* remote2) {
remote2->channel = "CCTV-5"; // 修改了同一个对象的内容
remote2 = new TV(); // 仅仅是改变了局部指针的指向,外部指针 remote1 纹丝不动!
}
如果在 C++ 里想做真正的"引用传递",你得写成 void changeTV(TV*& remote2)(传指针的引用),这样你修改 remote2 的指向,外面的指针才会跟着变。但 Java 底层根本没给你这种能力!
🏆 费曼总结检验
- String 是个只能看不能改的"防弹玻璃盒"(引用类型)。每次你以为修改了它,其实都是系统偷偷给你换了个新的。
- Java 传参 ,永远都是在"复印"。传基本类型就复印数字,传对象就复印遥控器(地址) 。因为你在函数里砸烂克隆遥控器,影响不到外面的原版遥控器,所以 Java 绝对是值传递!