Java 完全指南 / 04 - 变量与类型:基本类型、包装类、类型转换、var
04 - 变量与类型:基本类型、包装类、类型转换、var
变量声明与初始化
public class VariableDemo {
// 类变量(静态变量)—— 整个类共享
static int classCount = 0;
// 实例变量 —— 每个对象独立
String name;
int age;
public static void main(String[] args) {
// 局部变量 —— 方法内有效,必须初始化
int localVar = 42;
final double PI = 3.14159; // 常量(final)
System.out.println("局部变量: " + localVar);
System.out.println("常量: " + PI);
// 多变量声明
int a = 1, b = 2, c = 3;
// 变量命名规则
int studentAge = 20; // 驼峰命名(推荐)
int MAX_RETRY = 3; // 常量全大写下划线
String _private = "ok"; // 可以下划线开头(不推荐)
// int 1name = 1; // ❌ 不能以数字开头
// int class = 1; // ❌ 不能使用关键字
}
}
8 种基本数据类型(Primitive Types)
| 类型 | 大小 | 范围 | 默认值 | 示例 |
|---|---|---|---|---|
byte | 1 字节 | -128 ~ 127 | 0 | byte b = 100; |
short | 2 字节 | -32768 ~ 32767 | 0 | short s = 30000; |
int | 4 字节 | -2³¹ ~ 2³¹-1 | 0 | int i = 100000; |
long | 8 字节 | -2⁶³ ~ 2⁶³-1 | 0L | long l = 100L; |
float | 4 字节 | ±3.4E38 | 0.0f | float f = 3.14f; |
double | 8 字节 | ±1.7E308 | 0.0 | double d = 3.14; |
char | 2 字节 | 0 ~ 65535 | ‘\u0000’ | char c = 'A'; |
boolean | ~1 位 | true / false | false | boolean ok = true; |
public class PrimitiveTypes {
public static void main(String[] args) {
// 整数类型
byte byteVal = 127;
short shortVal = 32767;
int intVal = 2_147_483_647; // 下划线分隔,提高可读性
long longVal = 9_223_372_036_854_775_807L; // long 需要 L 后缀
// 浮点类型
float floatVal = 3.14f; // float 需要 f 后缀
double doubleVal = 3.141592653589793;
// 字符类型(Unicode)
char charA = 'A';
char charChinese = '中';
char charUnicode = '\u0041'; // Unicode 编码 'A'
// 布尔类型
boolean isTrue = true;
// 二进制、八进制、十六进制字面量
int binary = 0b1010; // 二进制: 10
int octal = 017; // 八进制: 15
int hex = 0xFF; // 十六进制: 255
System.out.println("byte: " + byteVal);
System.out.println("int 带下划线: " + intVal);
System.out.println("char 中文: " + charChinese);
System.out.println("二进制 0b1010 = " + binary);
System.out.println("十六进制 0xFF = " + hex);
}
}
包装类(Wrapper Types)
每种基本类型都有对应的包装类(位于 java.lang 包):
| 基本类型 | 包装类 | 范围常量 |
|---|---|---|
byte | Byte | Byte.MIN_VALUE / Byte.MAX_VALUE |
short | Short | Short.MIN_VALUE / Short.MAX_VALUE |
int | Integer | Integer.MIN_VALUE / Integer.MAX_VALUE |
long | Long | Long.MIN_VALUE / Long.MAX_VALUE |
float | Float | Float.MIN_VALUE / Float.MAX_VALUE |
double | Double | Double.MIN_VALUE / Double.MAX_VALUE |
char | Character | Character.MIN_VALUE / Character.MAX_VALUE |
boolean | Boolean | Boolean.TRUE / Boolean.FALSE |
自动装箱与拆箱
public class BoxingDemo {
public static void main(String[] args) {
// 自动装箱(Autoboxing):基本类型 → 包装类
Integer intObj = 42; // 编译器自动调用 Integer.valueOf(42)
Double doubleObj = 3.14;
// 自动拆箱(Unboxing):包装类 → 基本类型
int intVal = intObj; // 编译器自动调用 intObj.intValue()
double doubleVal = doubleObj;
// 包装类的用途
// 1. 集合中只能存包装类
java.util.List<Integer> list = new java.util.ArrayList<>();
list.add(1); // 自动装箱
int first = list.get(0); // 自动拆箱
// 2. 可以为 null(数据库字段映射)
Integer dbAge = null; // 数据库中该字段为 NULL
// 3. 类型转换工具方法
int parsed = Integer.parseInt("123");
double parsedDouble = Double.parseDouble("3.14");
String str = Integer.toString(42);
String binary = Integer.toBinaryString(255); // "11111111"
System.out.println("解析结果: " + parsed);
System.out.println("二进制: " + binary);
}
}
Integer 缓存陷阱
public class IntegerCacheDemo {
public static void main(String[] args) {
Integer a = 127;
Integer b = 127;
System.out.println(a == b); // true(缓存范围 -128~127)
Integer c = 128;
Integer d = 128;
System.out.println(c == d); // false(超出缓存,创建新对象)
System.out.println(c.equals(d)); // true(比较值,推荐用 equals)
// ⚠️ 永远使用 equals() 比较包装类的值!
}
}
⚠️
Integer缓存范围为 -128~127。==比较的是引用而非值,超出缓存范围会创建新对象。务必使用.equals()比较包装类!
类型转换
隐式转换(自动提升,Widening)
// 小类型 → 大类型,自动转换,无数据丢失
byte b = 10;
int i = b; // byte → int ✅
long l = i; // int → long ✅
float f = l; // long → float ✅
double d = f; // float → double ✅
// 自动提升规则
// byte → short → int → long → float → double
// char → int → long → float → double
显式转换(强制转换,Narrowing)
// 大类型 → 小类型,需要强制转换,可能丢失数据
double d = 3.99;
int i = (int) d; // 截断小数部分,结果为 3
int big = 130;
byte b = (byte) big; // 溢出!130 超出 byte 范围,结果为 -126
long l = 2147483648L;
int ii = (int) l; // 溢出!结果为 -2147483648
System.out.println("(int) 3.99 = " + i); // 3
System.out.println("(byte) 130 = " + b); // -126
System.out.println("(int) 2147483648L = " + ii); // -2147483648
数字与字符串互转
public class ConversionDemo {
public static void main(String[] args) {
// 数字 → 字符串
String s1 = String.valueOf(42);
String s2 = Integer.toString(42);
String s3 = 42 + ""; // 字符串拼接(不推荐)
// 字符串 → 数字
int i1 = Integer.parseInt("42");
double d1 = Double.parseDouble("3.14");
long l1 = Long.parseLong("1000000");
// 进制转换
String hex = Integer.toHexString(255); // "ff"
String bin = Integer.toBinaryString(10); // "1010"
int fromHex = Integer.parseInt("ff", 16); // 255
// 安全转换(避免 NumberFormatException)
Integer parsed = safeParseInt("abc");
System.out.println("安全解析: " + parsed); // null
}
static Integer safeParseInt(String s) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
return null;
}
}
}
var 局部变量类型推断(JDK 10+)
public class VarDemo {
public static void main(String[] args) {
// 编译器根据右侧推断类型
var name = "Java"; // 推断为 String
var age = 25; // 推断为 int
var list = new ArrayList<String>(); // 推断为 ArrayList<String>
var map = Map.of("key", "value"); // 推断为 Map<String, String>
// 增强 for 循环中使用
var items = List.of("A", "B", "C");
for (var item : items) {
System.out.println(item);
}
// for 循环中使用
for (var i = 0; i < 10; i++) {
System.out.print(i + " ");
}
}
}
var 使用限制
| 场景 | 是否可用 | 说明 |
|---|---|---|
| 局部变量 | ✅ | var x = 10; |
| for 循环 | ✅ | for (var i = 0; ...) |
| 增强 for | ✅ | for (var item : list) |
| try-with-resources | ✅ | try (var is = ...) |
| 类的字段 | ❌ | 必须显式声明类型 |
| 方法参数 | ❌ | 必须显式声明类型 |
| 方法返回类型 | ❌ | 必须显式声明类型 |
| 赋值为 null | ❌ | 无法推断类型 |
| Lambda | ❌ | var x = (a) -> a + 1; 不行 |
常量与枚举
public class ConstantsDemo {
// 编译时常量
public static final int MAX_SIZE = 100;
public static final String APP_NAME = "MyApp";
// 枚举类型
enum Season {
SPRING("春天", 1),
SUMMER("夏天", 2),
AUTUMN("秋天", 3),
WINTER("冬天", 4);
private final String chinese;
private final int order;
Season(String chinese, int order) {
this.chinese = chinese;
this.order = order;
}
public String getChinese() { return chinese; }
public int getOrder() { return order; }
}
public static void main(String[] args) {
Season s = Season.SPRING;
System.out.println(s.getChinese()); // 春天
// 枚举用于 switch
switch (s) {
case SPRING -> System.out.println("万物复苏");
case SUMMER -> System.out.println("烈日炎炎");
case AUTUMN -> System.out.println("秋高气爽");
case WINTER -> System.out.println("银装素裹");
}
// 枚举遍历
for (Season season : Season.values()) {
System.out.println(season + " -> " + season.getChinese());
}
}
}
⚠️ 注意事项
- 浮点数精度问题 —
0.1 + 0.2 != 0.3,金融计算使用BigDecimal。 - char 是无符号 2 字节 — 与 C/C++ 不同,Java 的 char 是 Unicode 字符。
- boolean 不能与整数互转 — 不像 C 语言,
if (1)在 Java 中不合法。 - Integer 比较用 equals —
==比较引用,超出缓存范围会出错。 - var 不是 dynamic — var 在编译期确定类型,之后不能改变类型。
💡 技巧
BigDecimal 精确计算:
BigDecimal price = new BigDecimal("19.99"); BigDecimal tax = new BigDecimal("0.08"); BigDecimal total = price.multiply(BigDecimal.ONE.add(tax)) .setScale(2, RoundingMode.HALF_UP);数字格式化:
NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.CHINA); System.out.println(fmt.format(12345.67)); // ¥12,345.67范围检查(JDK 16+):
// 使用 Math 检查溢出 int safe = Math.addExact(Integer.MAX_VALUE, 1); // 抛出 ArithmeticException
🏢 业务场景
- 数据库映射: 数据库 NULL 值用包装类接收(
Integer age而非int age),避免 NPE。 - 金额计算: 电商平台价格计算使用
BigDecimal,避免浮点精度丢失。 - 配置解析: 从配置文件读取的值是字符串,需要
Integer.parseInt()等方法转换。