V
Vel·ToolKit
简洁 · 高效 · 即开即用
ZH
第 2 章 / 共 20 章

变量、基本类型与字面量

8 种基本类型、包装类、var 推断、final 常量、装箱陷阱

8 种基本类型(primitive)

Java 区分基本类型和引用类型。基本类型直接存值、没有方法、有固定字节宽度;引用类型是对象,存的是地址。

类型      字节  默认值     范围
--------  ----  --------   --------------------------
byte       1    0          -128 ~ 127
short      2    0          -32768 ~ 32767
int        4    0          约 ±21 亿
long       8    0L         约 ±9.2×10^18
float      4    0.0f       单精度浮点
double     8    0.0d       双精度浮点
char       2    '\u0000'   一个 UTF-16 单元(0 ~ 65535)
boolean    1*   false      true / false(*JVM 实现而定)

声明与赋值

// Vars.java
public class Vars {
    public static void main(String[] args) {
        int age = 30;
        double price = 19.9;
        char letter = 'A';
        boolean ok = true;
        String name = "Alice";   // 引用类型

        // 多变量同时声明
        int x = 1, y = 2, z = 3;

        System.out.println(age + " " + price + " " + letter + " " + ok);
        System.out.println(name + " " + x + " " + y + " " + z);
    }
}

字面量与下划线分隔

数字字面量可以带类型后缀(L / f / d),整数支持二进制 0b、八进制 0、十六进制 0x 前缀。Java 7+ 允许下划线提升可读性(不影响值)。

// Literals.java
public class Literals {
    public static void main(String[] args) {
        long  big   = 10_000_000_000L;   // 必须 L 后缀(默认 int 装不下)
        float pi    = 3.14f;             // float 必须 f 后缀
        double d    = 1.0;               // 默认 double,d 后缀可省

        int hex     = 0xFF;              // 255
        int oct     = 010;               // 8
        int bin     = 0b1010;            // 10
        int million = 1_000_000;

        System.out.println(big);
        System.out.println(pi);
        System.out.println(d);
        System.out.println(hex + " " + oct + " " + bin + " " + million);
    }
}

包装类与自动装箱

8 种基本类型各有一个对应的包装类(Integer、Long、Double、Boolean…)。引用类型的集合(如 List<Integer>)必须用包装类,编译器自动在基本类型和包装类之间转换,称为"自动装箱 / 拆箱"。

// Boxing.java
import java.util.ArrayList;
import java.util.List;

public class Boxing {
    public static void main(String[] args) {
        Integer boxed = 42;          // 自动装箱:int -> Integer
        int unboxed = boxed;         // 自动拆箱:Integer -> int

        List<Integer> nums = new ArrayList<>();
        nums.add(1);                 // 自动装箱
        nums.add(2);
        int sum = 0;
        for (Integer n : nums) {
            sum += n;                // 自动拆箱
        }
        System.out.println(sum);     // 3
    }
}
// BoxingTrap.java
public class BoxingTrap {
    public static void main(String[] args) {
        Integer a = 100, b = 100;
        Integer c = 200, d = 200;
        System.out.println(a == b);        // true (在缓存范围)
        System.out.println(c == d);        // false(超出缓存)
        System.out.println(c.equals(d));   // true (正确做法)
    }
}

var 局部变量推断(Java 10+)

var 只能用于局部变量,编译器从右侧字面量推断类型。不是动态类型——类型仍然在编译期确定。

// Var.java
import java.util.ArrayList;

public class Var {
    public static void main(String[] args) {
        var count = 0;                       // int
        var name = "Alice";                  // String
        var list = new ArrayList<Integer>(); // ArrayList<Integer>

        list.add(1);
        list.add(2);
        System.out.println(count + " " + name + " " + list);
    }

    // var 不能用于字段、方法参数、方法返回值
    // private var bad;            // 编译错误
    // void f(var x) {}            // 编译错误
}

final 常量

final 修饰变量后只能赋一次值。习惯上常量名全大写、下划线分隔。

// Constants.java
public class Constants {
    static final double PI = 3.141592653589793;
    static final String APP_NAME = "VelToolKit";

    public static void main(String[] args) {
        final int max = 100;
        // max = 200;  // 编译错误:cannot assign a value to final variable
        System.out.println(PI + " " + APP_NAME + " " + max);
    }
}

类型转换

小范围 → 大范围自动转换(widening),反过来必须强制 (cast)(narrowing),可能丢失精度。

// Cast.java
public class Cast {
    public static void main(String[] args) {
        int i = 100;
        long l = i;          // 自动 widening
        double d = i;        // int -> double 自动

        double pi = 3.14;
        int truncated = (int) pi;   // 强制转换,丢小数:3

        long big = 10_000_000_000L;
        int overflow = (int) big;   // 溢出:1410065408

        System.out.println(l + " " + d + " " + truncated + " " + overflow);
    }
}

== vs equals 陷阱

== 比较基本类型是值比较;比较引用类型是"是不是同一对象"。比较字符串/包装类等内容是否相等,永远用 .equals()。

// EqualsTrap.java
public class EqualsTrap {
    public static void main(String[] args) {
        String a = "hello";
        String b = "hello";              // 字符串字面量池,同一对象
        String c = new String("hello");  // 显式 new,新对象

        System.out.println(a == b);       // true(同一池对象)
        System.out.println(a == c);       // false(不同对象)
        System.out.println(a.equals(c));  // true(内容相同,正确)
    }
}