引言:什么是变量?
在现实生活中,我们需要容器来存储物品。比如冰箱用来存放食物,衣柜用来存放衣物。在编程中,变量就是用来存储数据的"容器"。
可以把变量想象成一个贴有标签的盒子:
- 盒子上的标签就是变量名,用来标识这个盒子
- 盒子里装的东西就是变量的值
- 盒子的类型决定了它能装什么样的东西(只能装苹果、或只能装橘子)
变量类比
变量就像是便利店里的储物柜:
┌─────────────────┐
│ 标签: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位)
引用数据类型
用于存储对象的地址引用,或复杂的数组、字符串等数据
- String(字符串)
- 自定义类等
- Runnable
- Comparable
- 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会自动进行转换。这种转换是安全的,不会丢失数据。
自动类型转换示例
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)功能,使得基本类型和它们的包装类之间可以自动转换。
基本类型与包装类对应关系
| 基本类型 | 包装类 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| float | Float |
| double | Double |
| char | Character |
| boolean | Boolean |
自动装箱和拆箱示例
// 自动装箱:基本类型 → 包装类
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),基本类型无法做到
变量命名规则与规范
必须遵守的命名规则(硬性要求)
命名规范(软性要求,强烈推荐)
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关键字声明,命名全部大写