教程中心 / Java教程 / 变量和数据类型

变量和数据类型

20分钟 基础语法

引言:什么是变量?

在现实生活中,我们需要容器来存储物品。比如冰箱用来存放食物,衣柜用来存放衣物。在编程中,变量就是用来存储数据的"容器"。

可以把变量想象成一个贴有标签的盒子:

  • 盒子上的标签就是变量名,用来标识这个盒子
  • 盒子里装的东西就是变量的值
  • 盒子的类型决定了它能装什么样的东西(只能装苹果、或只能装橘子)

变量类比

变量就像是便利店里的储物柜:
┌─────────────────┐
│  标签:name     │  ← 变量名(用于识别)
│  类型:字符串柜  │  ← 数据类型(决定存储内容)
│  内容:"小明"    │  ← 变量的值(实际存储的数据)
└─────────────────┘

变量的声明和初始化

1. 先声明后赋值

这是最基本的变量使用方式,分两步进行:

// 第一步:声明变量(声明变量类型和名称)
int age;      // 声明一个名为age的整数变量

// 第二步:赋值(将具体的值存入变量)
age = 25;     // 给age变量赋值为25

2. 声明时直接初始化

在实际开发中,更常见的做法是声明和赋值一起完成:

// 声明的同时赋值
int age = 25;           // 整数类型
String name = "小明";   // 字符串类型
double height = 175.5;  // 浮点数类型
boolean isStudent = true; // 布尔类型

3. 同时声明多个同类型变量

可以使用逗号分隔同时声明多个变量:

int a = 1, b = 2, c = 3;
int x, y, z;  // 先声明后赋值
x = 10;
y = 20;
z = 30;

注意:变量必须先声明、后赋值、才能使用。否则会导致编译错误:"可能尚未初始化变量"。

Java的数据类型分类

Java的数据类型分为两大类,这是Java基础知识中最重要的概念之一:

基本数据类型(8种)

用于存储简单的单一数据值,如数字、字符、布尔值

整数类型
  • byte(1字节)
  • short(2字节)
  • int(4字节)
  • long(8字节)
浮点类型
  • float(4字节)
  • double(8字节)
字符类型
  • char(2字节)
布尔类型
  • boolean(1位)

引用数据类型

用于存储对象的地址引用,或复杂的数组、字符串等数据

类(Class)
  • String(字符串)
  • 自定义类等
接口(Interface)
  • Runnable
  • Comparable
数组(Array)
  • int[]
  • String[]

基本类型 vs 引用类型的核心区别:

  • 基本类型:变量直接存储值本身。如 int a = 5; 变量a存储的就是数字5
  • 引用类型:变量存储的是对象的"地址"(引用),而不是对象本身

基本数据类型详解

1. 整数类型(byte, short, int, long)

整数类型用于存储没有小数部分的数值。选择合适的整数类型可以节省内存空间。

类型 占用空间 取值范围 默认值 使用建议
byte 1字节 -128 ~ 127 0 处理二进制数据、网络传输
short 2字节 -32768 ~ 32767 0 兼容性考虑(很少使用)
int 4字节 约-21亿 ~ 21亿
-2,147,483,648 ~ 2,147,483,647
0 最常用,日常整数运算首选
long 8字节 约-922亿亿 ~ 922亿亿 0L 处理大数值,如时间戳、大金额

为什么int是最常用的整数类型?

因为int类型的大小(4字节)对于大多数日常应用来说刚刚好:

  • 能表示约±21亿的数值,对于一般计数、索引、年龄、工资等完全够用
  • CPU对int类型的处理效率最高
  • JVM规范中,int是虚拟机操作码(opcode)的标准类型

long类型的使用注意事项

long类型的取值范围比int大得多,但使用时需要注意:

long bigNumber = 10000000000L;  // 必须加L后缀,否则会被当作int处理
long timestamp = System.currentTimeMillis();  // 时间戳常用long

2. 浮点类型(float, double)

浮点类型用于存储带小数点的数值,即实数。

类型 占用空间 取值范围 精度 默认值 使用建议
float 4字节 ±3.4E38 6-7位有效数字 0.0f 内存敏感时使用(需要加F后缀)
double 8字节 ±1.7E308 15-16位有效数字 0.0 最常用,默认小数类型

重要警告:浮点数不适合精确计算!

由于浮点数的表示方式(IEEE 754标准),浮点数在计算时可能产生精度误差。例如:

System.out.println(0.1 + 0.2);  // 输出:0.30000000000000004
System.out.println(1.0 - 0.9);  // 输出:0.09999999999999998

因此,涉及金钱计算时,应使用BigDecimal类,而不是float或double。

float类型的使用

float pi = 3.14159f;   // 必须加F/f后缀
float rate = 0.5f;      // 百分比等场景使用float

3. 字符类型(char)

char用于存储单个字符,使用Unicode编码,占用2个字节。

字符的多种表示方式

char letter = 'A';           // 直接用单引号包围单个字符
char chinese = '中';          // 可以存储中文
char digit = '5';            // 可以存储数字字符(注意:这是字符,不是数字5)
char unicode = '\u0041';     // 使用Unicode编码,\u0041表示字符'A'
char ascii = 65;             // 可以直接用ASCII码值(65对应字符'A')

字符和字符串的区别:

  • char:单引号,用于表示单个字符,如 'A'
  • String:双引号,用于表示字符串,如 "Hello"

4. 布尔类型(boolean)

布尔类型只有两个可能的值:true(真)false(假)

布尔类型的用途

boolean isStudent = true;      // 是否是学生
boolean isAdult = age >= 18;   // 是否成年(根据条件判断)
boolean hasPassed = score >= 60; // 是否及格

布尔类型的特点:

  • boolean类型只能是true或false,不能是0或1
  • 主要用于条件判断,如if语句、循环条件
  • boolean类型不能与其他基本类型相互转换

引用数据类型

1. String字符串

String是Java中最常用的引用类型,用于处理文本。虽然String不是Java的基本数据类型,但由于使用频率极高,我们需要特别关注。

String的特点

  • 不可变性:String一旦创建,内容不可更改。所有看起来修改String的操作,实际上是创建了新的String对象
  • 字符串常量池:Java会复用已创建的字符串常量,节省内存
  • 丰富的API:提供了大量操作字符串的方法

String的创建方式对比

// 方式1:直接赋值(推荐)
String s1 = "Hello";

// 方式2:使用构造方法
String s2 = new String("Hello");

// 对比
String s3 = "Hello";  // 可能在字符串常量池中创建
String s4 = new String("Hello");  // 一定会在堆中创建新对象

2. 数组

数组是一种引用类型,用于存储相同类型的多个元素。

int[] numbers = {1, 2, 3, 4, 5};  // 整数数组
String[] names = {"Alice", "Bob"};  // 字符串数组

3. 类和接口

当我们定义一个类或接口时,它们就成为一种数据类型,可以用来声明变量。

// Person是一个自定义类
Person p = new Person();  // 创建Person类的实例

// Runnable是一个接口
Runnable r = () -> System.out.println("运行中");

数据类型的默认值

当一个变量作为类的成员变量(实例变量或静态变量)被声明但未初始化时,它会有一个默认值。但局部变量(如方法内的变量)没有默认值,必须手动初始化

数据类型 默认值 说明
byte, short, int, long 0 整数默认值为0
float, double 0.0 浮点数默认值为0.0
char '\u0000' 空字符(不是空格)
boolean false 布尔默认值为false
引用类型(String等) null 表示不指向任何对象

重要:局部变量必须初始化!

public void test() {
    int a;           // 局部变量
    System.out.println(a);  // 编译错误:变量a可能尚未初始化
}

类型转换

类型转换是将一种数据类型转换为另一种数据类型的过程。Java中的类型转换分为两种:自动类型转换和强制类型转换。

1. 自动类型转换(隐式转换)

当把一个取值范围小的类型赋给一个取值范围大的类型时,Java会自动进行转换。这种转换是安全的,不会丢失数据。

byte
short
int
long
float
double
char
int
long
float
double

自动类型转换示例

int i = 100;
long l = i;      // int自动转换为long
double d = i;    // int自动转换为double

char c = 'A';
int code = c;   // char自动转换为int(输出65)

2. 强制类型转换(显式转换)

当把一个取值范围大的类型赋给一个取值范围小的类型时,必须使用强制转换符。这种转换可能会丢失数据

强制转换可能导致数据丢失!当大范围数值超出小范围类型的表示范围时,会发生"溢出",导致结果不正确。

强制类型转换示例

double pi = 3.14159;
int num = (int) pi;   // 强制转换为int,小数部分被丢弃,输出3

int bigNum = 130;
byte small = (byte) bigNum;  // 发生溢出,输出-126(不是130)

// 溢出演示
int intValue = 200;
byte byteValue = (byte) intValue;
System.out.println(byteValue);  // 输出:-56(因为byte范围是-128~127)

常见溢出情况

// 计算员工工资(单位:元)
int monthlySalary = 3000;
int months = 12;
int yearlySalary = monthlySalary * months;  // 正常:36000

// 但如果计算很多人的工资总和
long totalSalary = monthlySalary * months;  // 结果正确,因为赋值给long

// 注意:如果先计算再赋值给int
int overflow = (int)(monthlySalary * months * 100L);  // 使用L避免中间计算溢出

3. 自动装箱与拆箱

从Java 5开始,引入了自动装箱(Boxing)和拆箱(Unboxing)功能,使得基本类型和它们的包装类之间可以自动转换。

基本类型与包装类对应关系

基本类型包装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

自动装箱和拆箱示例

// 自动装箱:基本类型 → 包装类
Integer i = 100;      // 自动将int转换为Integer

// 自动拆箱:包装类 → 基本类型
int j = new Integer(100);  // 自动将Integer转换为int

// 在集合中的使用
List list = new ArrayList<>();
list.add(10);        // 自动装箱:int → Integer
int value = list.get(0);  // 自动拆箱:Integer → int

为什么需要包装类?

  • 包装类提供了更多的方法,如Integer.parseInt()、Integer.toBinaryString()等
  • 泛型类型不能使用基本类型,只能使用包装类
  • 某些场景需要表示"无值"(null),基本类型无法做到

变量命名规则与规范

必须遵守的命名规则(硬性要求)

变量名必须以字母、_(下划线)或$(美元符)开头
变量名可以包含数字,但不能以数字开头
不能使用Java保留字(如if、for、class、public等)
变量名区分大小写(age和Age是不同的变量)

命名规范(软性要求,强烈推荐)

1. 驼峰命名法(Camel Case)

场景规范示例
变量名、方法名首字母小写,之后每个单词首字母大写studentName, getAge
类名首字母大写,之后每个单词首字母大写Student, HelloWorld
常量全部大写,单词间用下划线分隔MAX_VALUE, PI

2. 见名知意

❌ 不推荐:
int n;        // 不知道n代表什么
int x, y, z;  // 含义不清
String s;     // s是什么?
✓ 推荐:
int age;           // 代表年龄
int studentCount;  // 学生数量
String name;      // 代表姓名

常见命名示例

// 变量命名示例
int age = 25;                      // ✓ 好:简单明了
String studentName = "张三";        // ✓ 好:驼峰命名,见名知意
double accountBalance = 1000.50;   // ✓ 好:描述了账户余额
boolean isActive = true;           // ✓ 好:布尔变量通常用is开头

// 常见错误
int a = 25;                        // ❌ 差:过于简单
int numberOfStudents = 25;         // ✓ 好:清晰表达含义
String name_of_student = "李四";    // ❌ 不推荐:使用了下划线(Java中不用)
String $name = "王五";              // ⚠️ 技术上可以,但不推荐

常量

常量是值不可改变的变量,使用final关键字声明。常量一旦被赋值,就不能再被修改。

为什么使用常量?

  • 防止意外修改:常量一旦设定,代码中无法更改,提高程序安全性
  • 便于维护:如果需要修改常量值,只需在一处修改,避免遗漏
  • 提高可读性:使用有名称的常量比使用字面数值更易理解

常量的声明和使用

// 声明常量
final double PI = 3.14159265359;
final int MAX_RETRY_COUNT = 3;
final String APP_NAME = "学生管理系统";

// 使用常量
double area = PI * radius * radius;

// ❌ 错误:常量不能被修改
// PI = 3.14;  // 编译错误:cannot assign a value to final variable PI

常量命名规范:常量名通常全部大写,多个单词之间用下划线分隔,如MAX_VALUE、DEFAULT_TIMEOUT等。

小结

  • 变量三要素:类型(决定存储内容)、名称(用于引用)、值(存储的数据)
  • 基本数据类型(8种):byte、short、int、long、float、double、char、boolean
  • 引用数据类型:类(如String)、接口、数组等,存储的是对象的引用而非对象本身
  • 整数类型中int最常用,浮点类型中double最常用
  • 浮点数不适合精确计算,涉及金钱计算应使用BigDecimal
  • 类型转换:自动转换(安全)和强制转换(可能丢失数据)
  • 自动装箱/拆箱:基本类型与包装类之间的自动转换
  • 变量命名应遵循驼峰命名法,见名知意
  • 常量使用final关键字声明,命名全部大写
☕ Java 在线代码编辑器
📝 运行结果