Java 一共有多少种数据类型?——从 8 种基本类型到完整 Java 类型体系
本文系统梳理 Java 的完整类型体系,从 **8 种基本数据类型** 出发,进一步介绍类、接口、数组、类型变量以及泛型中的参数化类型、通配符、交叉类型等概念,并解释 `String`、`Integer`、`void`、`var`、`null` 等常见易混点,帮助建立完整、严谨的 Java 类型系统认知。
在学习 Java 时,我们经常会看到一句话:
Java 有 8 种基本数据类型。
这句话本身没有错,但它只回答了“Java 有多少种基本数据类型”,并没有回答“Java 一共有多少种数据类型”。
如果把 Java 的完整类型系统展开,我们会发现:
byte、int、double等只是基本类型;String、Student、ArrayList属于类类型;List、Runnable属于接口类型;int[]、String[]属于数组类型;- 泛型中的
T属于类型变量; List<String>属于参数化类型;? extends Number、Number & Comparable<?>等则属于 Java 泛型和类型推导体系中的高级类型结构。
因此,Java 并不存在一个“所有具体类型加起来一共 N 种”的固定答案。
原因很简单:程序员可以不断定义新的类、接口、数组组合和泛型类型。
这篇文章将从 Java 语言规范的视角,把 Java 类型体系完整梳理一遍。
一、先给出结论:Java 类型到底有多少种?
如果问题是:
Java 有多少种基本数据类型?
答案是:
8 种。
byte
short
int
long
float
double
char
boolean
如果问题是:
Java 的类型主要分为哪两大类?
最标准的回答是:
Java Type
├── Primitive Type 基本类型
└── Reference Type 引用类型
其中引用类型进一步包括:
Reference Type
├── Class Type 类类型
├── Interface Type 接口类型
├── Type Variable 类型变量
└── Array Type 数组类型
此外,Java 语言中还存在一个特殊的:
null type
但它不是普通意义上可以声明变量的类型,也不应该简单地和基本类型、引用类型并列理解。
所以,真正严谨的结论是:
Java 固定只有 8 种基本类型;引用类型则没有固定数量,因此 Java 的所有具体类型不存在一个固定总数。
二、Java 类型体系总览
先建立整体认识:
Java 类型系统
│
├── 1. Primitive Type 基本类型
│ │
│ ├── Numeric Type 数值类型
│ │ │
│ │ ├── Integral Type 整数类型
│ │ │ ├── byte
│ │ │ ├── short
│ │ │ ├── int
│ │ │ ├── long
│ │ │ └── char
│ │ │
│ │ └── Floating-Point Type 浮点类型
│ │ ├── float
│ │ └── double
│ │
│ └── boolean
│
└── 2. Reference Type 引用类型
│
├── Class Type 类类型
│ ├── 普通 class
│ ├── enum
│ └── record
│
├── Interface Type 接口类型
│ ├── 普通 interface
│ └── annotation interface
│
├── Type Variable 类型变量
│ └── T / E / K / V ...
│
└── Array Type 数组类型
├── int[]
├── String[]
├── Student[]
└── int[][] ...
除此之外,Java 的泛型和类型推导机制中还会出现:
Parameterized Type 参数化类型
Raw Type 原始类型
Wildcard 通配符
Intersection Type 交叉类型
null type null 的特殊类型
这些概念不能全部简单理解成与 int、String 同一级别的“普通数据类型”,但它们共同构成了 Java 完整的类型系统。
三、基本数据类型:固定只有 8 种
Java 的基本类型,也叫:
Primitive Type
它们不是对象,不属于类体系,也不继承 Object。
8 种基本类型如下:
| 分类 | 类型 | 位数 | 示例 |
| ---- | --------- | -------------------------------------- | ------------------- |
| 整数 | byte | 8 | byte a = 10; |
| 整数 | short | 16 | short b = 1000; |
| 整数 | int | 32 | int c = 100000; |
| 整数 | long | 64 | long d = 100L; |
| 浮点 | float | 32 | float e = 3.14F; |
| 浮点 | double | 64 | double f = 3.14; |
| 字符 | char | 16 | char g = 'A'; |
| 布尔 | boolean | JVM 规范不按普通整数位宽定义其存储实现 | boolean h = true; |
四、整数类型其实有 5 种
很多教程会说:
整数类型:
byte
short
int
long
从日常编程角度这样说没有问题。
但是从 Java 类型系统角度,char 也属于:
Integral Type
因此更加严谨的分类是:
Integral Type
├── byte
├── short
├── int
├── long
└── char
例如:
char c = 'A';
字符 'A' 对应 Unicode 编码值,因此 char 可以参与部分整数运算。
例如:
char c = 'A';
System.out.println((int) c);
输出:
65
所以 char 虽然通常用于表示字符,但从 Java 语言的类型分类来看,它属于整数类型体系。
五、浮点类型:float 与 double
Java 有两种浮点类型:
float
double
float
float price = 3.14F;
必须注意:
3.14
默认是 double。
因此赋值给 float 时通常需要:
3.14F
double
double pi = 3.1415926;
Java 浮点字面量默认就是 double。
在一般科学计算和普通业务计算中,double 使用更加广泛。
但是对于金融金额:
double money = 0.1 + 0.2;
可能出现浮点精度问题,因此通常会使用:
BigDecimal
注意:
BigDecimal
不是基本类型,而是一个类。
六、boolean:逻辑类型
Java 中只有一个布尔基本类型:
boolean
只有两个逻辑值:
true
false
例如:
boolean login = true;
if (login) {
System.out.println("登录成功");
}
与 C 语言不同,Java 不允许直接把整数当作布尔值。
下面代码错误:
int a = 1;
if (a) {
}
Java 要求 if 条件必须最终产生布尔结果。
正确:
if (a != 0) {
}
七、引用类型是什么?
除了 8 种基本类型之外,Java 中大量类型都属于:
Reference Type
例如:
String name = "LingXi";
Student student = new Student();
List<String> list = new ArrayList<>();
int[] numbers = new int[10];
其中:
String
Student
List<String>
ArrayList<String>
int[]
全部属于引用类型体系。
引用变量通常保存的不是对象内容本身,而是对对象的引用。
可以简单理解:
变量
│
↓
引用
│
↓
堆中的对象
例如:
Student student = new Student();
可以抽象理解为:
student
│
│ 引用
↓
Student 对象
八、类类型:Class Type
最常见的引用类型就是类类型。
例如:
String
Object
Integer
Scanner
ArrayList
Thread
Student
User
Order
假设我们定义:
class Student {
String name;
int age;
}
那么:
Student student = new Student();
这里的:
Student
就是一个类类型。
九、普通 class、enum、record 都属于类体系
Java 中的类类型不只是普通 class。
还包括一些特殊形式。
普通类
class Student {
}
Student 是类类型。
枚举类型 enum
enum Gender {
MALE,
FEMALE
}
可以:
Gender gender = Gender.MALE;
Gender 属于一种特殊的类类型。
记录类型 record
Java 中还可以定义:
record Student(String name, int age) {
}
使用:
Student student = new Student("LingXi", 21);
record 也是一种特殊的类声明形式,其产生的类型仍属于类类型体系。
因此可以这样理解:
Class Type
├── 普通 class
├── enum
└── record
十、接口类型:Interface Type
接口本身也是一种引用类型。
例如:
interface Flyable {
void fly();
}
定义:
class Bird implements Flyable {
@Override
public void fly() {
System.out.println("Flying...");
}
}
可以:
Flyable bird = new Bird();
这里:
Flyable
就是接口类型。
Java 标准库中大量类型都是接口,例如:
List
Set
Map
Runnable
Comparable
Serializable
Collection
例如:
List<String> list = new ArrayList<>();
变量声明类型:
List<String>
属于接口类型。
对象实际类型:
ArrayList<String>
属于类类型。
这也是 Java 面向接口编程的重要基础。
十一、注解也是特殊的接口类型
Java 中:
@interface MyAnnotation {
}
定义的是注解类型。
常见注解包括:
@Override
@Deprecated
@SuppressWarnings
@Test
从 Java 类型系统角度,可以把它理解为特殊的接口类型。
因此:
Interface Type
├── 普通 interface
└── annotation interface
十二、数组也是引用类型
这是 Java 初学阶段非常重要的一点:
int是基本类型,但int[]是引用类型。
例如:
int[] numbers = new int[10];
其中:
int
属于:
Primitive Type
但是:
int[]
属于:
Array Type
→ Reference Type
同理:
String[] names;
Student[] students;
int[][] matrix;
全部属于数组类型,也全部属于引用类型。
十三、为什么 Java 的类型总数无法固定?
假设 Java 只有:
int[]
这一种数组类型,那还可以统计。
问题是数组维度可以不断变化:
int[]
int[][]
int[][][]
int[][][][]
...
对象类型也可以不断定义:
class Student {
}
class Teacher {
}
class User {
}
class Order {
}
每定义一个新的类,就产生一个新的类型。
所以:
Java 的所有具体引用类型没有固定数量。
这就是为什么“Java 一共有多少种数据类型”不能简单回答一个数字。
十四、类型变量:Type Variable
泛型出现之后,还需要理解:
Type Variable
例如:
class Box<T> {
T value;
}
这里的:
T
就是一个类型变量。
它代表:
以后由具体使用者决定这里是什么类型。
例如:
Box<String> box1 = new Box<>();
Box<Integer> box2 = new Box<>();
此时:
T → String
或者:
T → Integer
常见泛型类型变量名称有:
T Type
E Element
K Key
V Value
R Result
例如:
Map<K, V>
十五、参数化类型:Parameterized Type
例如:
List<String>
List<Integer>
Map<String, Integer>
Optional<Student>
都属于参数化后的泛型类型。
例如:
List<String> names = new ArrayList<>();
这里可以理解成:
泛型声明:
List<E>
↓
把 E 替换为 String
↓
List<String>
因此:
List<String>
属于参数化类型。
但是需要注意:
参数化类型并不是 Java 顶层类型分类中新增加的第三大类。
List<String> 本质仍然建立在类或接口类型体系之上。
十六、Raw Type:原始类型
看下面两种写法:
List<String> list = new ArrayList<>();
以及:
List list = new ArrayList();
第二种没有提供泛型参数:
List
这叫:
Raw Type
原始类型
Raw Type 主要用于兼容 Java 5 引入泛型之前的旧代码。
现代 Java 开发中通常不建议使用。
因为它会失去泛型提供的编译期类型安全。
例如:
List list = new ArrayList();
list.add("Hello");
list.add(100);
list.add(new Student());
编译器很难提供严格的元素类型约束。
而:
List<String> list = new ArrayList<>();
只能正常添加字符串:
list.add("Hello");
下面会直接编译错误:
list.add(100);
十七、Wildcard:泛型通配符
Java 泛型中还有:
?
? extends T
? super T
例如:
List<?> list;
表示:
一个元素具体类型未知的 List。
再例如:
List<? extends Number>
表示:
List 中元素类型是 Number 或 Number 的某个子类型。
例如可能是:
List<Integer>
List<Double>
List<Long>
再例如:
List<? super Integer>
表示:
元素类型是 Integer 或 Integer 的某个父类型。
泛型中经常会提到:
PECS
即:
Producer Extends
Consumer Super
简单理解:
读取数据为主:
? extends T
写入数据为主:
? super T
这是 Java 泛型中非常重要的知识点。
十八、Intersection Type:交叉类型
Java 还存在:
Intersection Type
即:
A & B
表示一个类型必须同时满足多个约束。
例如:
<T extends Number & Comparable<T>>
其中:
Number & Comparable<T>
就是交叉类型结构。
意思是:
T 必须:
是 Number 的子类型
并且
实现 Comparable<T>
例如:
public static <T extends Number & Comparable<T>>
void print(T value) {
System.out.println(value);
}
交叉类型还可能出现在强制类型转换中:
(Runnable & java.io.Serializable) () -> {
System.out.println("Hello");
};
这里要求 Lambda 对象同时满足:
Runnable
+
Serializable
十九、null 是什么类型?
这是 Java 类型系统中很容易被忽略的一个特殊概念。
例如:
String name = null;
Student student = null;
Object object = null;
为什么 null 可以赋值给不同的引用类型?
因为 Java 语言中存在一个特殊的:
null type
它唯一对应的值就是:
null
但是不能写:
null value;
因为:
null
不是一个可以直接作为类型名称使用的关键字类型。
所以更加准确地说:
null是空引用字面量,它具有一个特殊的 null type,并可以转换成引用类型。
二十、基本类型与引用类型最核心的区别
例如:
int a = 10;
和:
Student student = new Student();
虽然都叫“变量”,但两者属于完全不同的类型体系。
可以粗略理解:
基本类型变量
a
↓
10
而引用类型:
student
│
↓
对象引用
│
↓
Student 对象
常见区别如下:
| 对比项 | 基本类型 | 引用类型 |
| --------------- | -------------- | ---------------------- |
| 示例 | int | String |
| 是否对象 | 否 | 通常用于引用对象/数组 |
| 是否继承 Object | 否 | 类和数组等进入引用体系 |
| 默认值 | 0、false等 | null |
| 能否为 null | 不能 | 可以 |
| 泛型中直接使用 | 不能 | 可以 |
例如:
List<int> list;
错误。
必须:
List<Integer> list;
因为 Java 泛型使用的是引用类型体系。
二十一、包装类不是基本类型
Java 为 8 种基本类型分别提供了包装类。
| 基本类型 | 包装类 |
| --------- | ----------- |
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
例如:
int age = 21;
Integer boxedAge = 21;
这两个类型完全不同。
int
↓
Primitive Type
而:
Integer
↓
Class Type
↓
Reference Type
Java 可以通过:
Autoboxing
自动装箱
自动完成:
Integer a = 10;
逻辑上相当于把:
int
包装成:
Integer
反过来则叫:
Unboxing
自动拆箱
例如:
Integer a = 10;
int b = a;
二十二、String 到底是什么类型?
很多 Java 初学者会产生疑问:
String name = "LingXi";
看起来和:
int age = 21;
非常像。
于是容易误认为:
String 是一种基本数据类型
这是错误的。
String 的真实身份是:
java.lang.String
↓
Class Type
↓
Reference Type
也就是说:
String是 Java 提供的一个类。
只不过 Java 对字符串字面量提供了非常方便的语法:
String name = "LingXi";
所以使用体验看起来很像基本类型。
二十三、Object 是所有类型的父类吗?
经常看到一句话:
Object 是 Java 所有类型的父类。
这句话也需要修正。
更加准确的是:
Object是 Java 类层次结构中的根类,大多数对象最终都属于 Object 体系。
例如:
Object
↑
String
Integer
Student
ArrayList
Thread
...
但是:
int
double
boolean
char
这些基本类型不是类。
所以:
int
并不继承:
Object
例如:
int a = 10;
这里 a 不是对象。
但是自动装箱之后:
Integer a = 10;
此时:
Integer
↓
Number
↓
Object
就进入了对象类型体系。
二十四、void 是不是第 9 种基本数据类型?
不是。
有些旧教程会把:
void
和 8 种基本类型放在一起。
例如:
public void test() {
}
这里:
void
表示:
这个方法不返回任何值。
但是不能:
void value;
因此:
void不属于 Java 的 8 种基本数据类型。
学习时最好不要背:
Java 有 9 种基本类型,包括 void
正确答案始终是:
8 种基本类型
二十五、var 是不是一种数据类型?
也不是。
Java 10 引入了局部变量类型推断:
var name = "LingXi";
编译器会推断:
name 的类型是 String
等价理解:
String name = "LingXi";
再例如:
var age = 21;
编译器推断:
int
再例如:
var list = new ArrayList<String>();
推断为:
ArrayList<String>
所以:
var
不是数据类型。
它只是:
局部变量类型推断语法
二十六、为什么泛型不能直接使用 int?
例如:
List<int> numbers;
会编译失败。
因为 Java 泛型的类型参数要求使用引用类型。
所以必须写:
List<Integer> numbers;
Java 会通过自动装箱,把:
int
转换为:
Integer
例如:
List<Integer> numbers = new ArrayList<>();
numbers.add(10);
实际上这里发生了:
10
↓
int
↓
自动装箱
↓
Integer
这也是理解基本类型与引用类型区别之后非常自然的一个结论。
二十七、为什么 Java 类型没有固定总数?
现在可以回答最开始的问题。
Java 固定的基本类型只有:
8 种
但是程序员可以不断创建:
class Student {
}
class Teacher {
}
class User {
}
class Order {
}
class Product {
}
于是:
Student
Teacher
User
Order
Product
全部成为新的类型。
还可以产生:
Student[]
Student[][]
List<Student>
Map<String, Student>
Optional<Student>
所以 Java 的具体类型数量理论上可以不断增加。
因此不能说:
Java 一共有 8 种数据类型
更加准确的说法应该是:
Java 一共有 8 种基本数据类型,而引用类型没有固定数量。
二十八、完整 Java 类型知识结构
最后把整个知识体系整理成一棵树:
Java Type System
│
├── Primitive Type
│ │
│ ├── Numeric Type
│ │ │
│ │ ├── Integral Type
│ │ │ ├── byte
│ │ │ ├── short
│ │ │ ├── int
│ │ │ ├── long
│ │ │ └── char
│ │ │
│ │ └── Floating-Point Type
│ │ ├── float
│ │ └── double
│ │
│ └── boolean
│
└── Reference Type
│
├── Class Type
│ ├── 普通 class
│ ├── enum
│ └── record
│
├── Interface Type
│ ├── interface
│ └── annotation interface
│
├── Type Variable
│ └── T / E / K / V ...
│
└── Array Type
├── int[]
├── String[]
├── Student[]
└── int[][] ...
围绕这套核心类型系统,还会出现:
Parameterized Type
Raw Type
Wildcard
Intersection Type
null type
它们主要出现在:
泛型
类型推导
类型转换
编译器类型检查
等更加高级的 Java 场景中。
二十九、考试、面试应该怎么回答?
不同问题,要给不同层级的答案。
问:Java 有多少种基本数据类型?
回答:
Java 有 8 种基本数据类型:
byte、short、int、long、float、double、char、boolean。
问:Java 数据类型分为哪两大类?
回答:
Java 类型主要分为基本类型和引用类型。
Primitive Type
Reference Type
问:Java 的引用类型有哪些?
回答:
Java 引用类型主要包括类类型、接口类型、类型变量和数组类型。
Class Type
Interface Type
Type Variable
Array Type
问:String 是基本类型吗?
回答:
不是。
String是java.lang.String类,因此属于引用类型中的类类型。
问:数组是基本类型还是引用类型?
回答:
数组属于引用类型。即使数组元素是
int,int[]本身依然是引用类型。
问:Integer 是基本类型吗?
回答:
不是。
Integer是int对应的包装类,属于类类型。
问:void 是基本类型吗?
回答:
不是。
void用于表示方法没有返回值,不属于 Java 的 8 种基本类型。
问:var 是类型吗?
回答:
不是。
var是局部变量类型推断语法,变量最终仍然拥有具体的静态类型。
三十、最终总结
如果只记一句话:
Java 固定只有 8 种基本数据类型,但 Java 的所有具体类型没有固定总数量。
8 种基本类型:
byte
short
int
long
float
double
char
boolean
Java 类型体系最核心的结构:
Java Type
├── Primitive Type
└── Reference Type
引用类型主要包括:
Class Type
Interface Type
Type Variable
Array Type
除此之外,还应该理解:
Parameterized Type
Raw Type
Wildcard
Intersection Type
null type
最终真正需要建立的思维不是:
Java = 背 8 个数据类型
而是:
Java 类型系统
│
├── 基本值
│
├── 对象
│
├── 接口抽象
│
├── 数组
│
├── 泛型
│
└── 编译器类型约束
当这套类型体系真正建立起来之后,后续学习:
面向对象
集合框架
泛型
反射
Lambda
Stream
Java API
Spring
都会更加自然。
因为它们本质上都建立在 Java 的类型系统之上。