强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

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)

类型大小范围默认值示例
byte1 字节-128 ~ 1270byte b = 100;
short2 字节-32768 ~ 327670short s = 30000;
int4 字节-2³¹ ~ 2³¹-10int i = 100000;
long8 字节-2⁶³ ~ 2⁶³-10Llong l = 100L;
float4 字节±3.4E380.0ffloat f = 3.14f;
double8 字节±1.7E3080.0double d = 3.14;
char2 字节0 ~ 65535‘\u0000’char c = 'A';
boolean~1 位true / falsefalseboolean 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 包):

基本类型包装类范围常量
byteByteByte.MIN_VALUE / Byte.MAX_VALUE
shortShortShort.MIN_VALUE / Short.MAX_VALUE
intIntegerInteger.MIN_VALUE / Integer.MAX_VALUE
longLongLong.MIN_VALUE / Long.MAX_VALUE
floatFloatFloat.MIN_VALUE / Float.MAX_VALUE
doubleDoubleDouble.MIN_VALUE / Double.MAX_VALUE
charCharacterCharacter.MIN_VALUE / Character.MAX_VALUE
booleanBooleanBoolean.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; ...)
增强 forfor (var item : list)
try-with-resourcestry (var is = ...)
类的字段必须显式声明类型
方法参数必须显式声明类型
方法返回类型必须显式声明类型
赋值为 null无法推断类型
Lambdavar 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());
        }
    }
}

⚠️ 注意事项

  1. 浮点数精度问题0.1 + 0.2 != 0.3,金融计算使用 BigDecimal
  2. char 是无符号 2 字节 — 与 C/C++ 不同,Java 的 char 是 Unicode 字符。
  3. boolean 不能与整数互转 — 不像 C 语言,if (1) 在 Java 中不合法。
  4. Integer 比较用 equals== 比较引用,超出缓存范围会出错。
  5. var 不是 dynamic — var 在编译期确定类型,之后不能改变类型。

💡 技巧

  1. 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);
    
  2. 数字格式化

    NumberFormat fmt = NumberFormat.getCurrencyInstance(Locale.CHINA);
    System.out.println(fmt.format(12345.67));  // ¥12,345.67
    
  3. 范围检查(JDK 16+):

    // 使用 Math 检查溢出
    int safe = Math.addExact(Integer.MAX_VALUE, 1); // 抛出 ArithmeticException
    

🏢 业务场景

  • 数据库映射: 数据库 NULL 值用包装类接收(Integer age 而非 int age),避免 NPE。
  • 金额计算: 电商平台价格计算使用 BigDecimal,避免浮点精度丢失。
  • 配置解析: 从配置文件读取的值是字符串,需要 Integer.parseInt() 等方法转换。

📖 扩展阅读