Skip to content

常用类(Object、包装类、Math)

概述

Java 中 Object 是所有类的根类,其 equals / hashCode / toString 的约定直接影响对象在集合、比较和调试中的行为。包装类(如 Integer、Double)将基本类型封装为对象,支持自动装箱与拆箱,是集合和泛型中不可或缺的一环。Math 则提供常用的数学运算与常量。本节从「值语义」与「日常开发」两个角度介绍这三类常用 API。

前置建议

已掌握 类与对象封装与访问修饰符,以及 变量与数据类型 中的基本类型与引用类型。


Object 与通用方法

Object 的地位

在 Java 中,所有类(除 Object 自身)都直接或间接继承自 Object。因此,任何对象都可以调用 Object 提供的方法,例如 equalshashCodetoStringgetClassclonenotify/notifyAll/wait 等。日常开发中最常需要重写的是 equalshashCodetoString

equals 与 hashCode 契约

equals 用于判断两个对象在「业务含义」上是否相等;hashCode 返回对象的哈希值,用于基于哈希的集合(如 HashMap、HashSet)。Java 规定:

  1. equals 相等 → 两对象的 hashCode 必须相等
  2. equals 不相等 → hashCode 可以相等(哈希冲突),但最好尽量不同以提高散列性能。
  3. 重写 equals必须同时重写 hashCode,否则在 HashMap、HashSet 等集合中会出现「逻辑上相等但查不到」或「重复元素」等错误行为。

注意

重写 equals 时必须同时重写 hashCode,否则在基于哈希的集合中行为异常。

正确重写 equals

推荐步骤:先判断是否同一引用,再判断 null 和类型,最后按业务字段逐项比较。基本类型用 ==,引用类型用 Objects.equals 以安全处理 null。

java
import java.util.Objects;

public class User {
    private String name;
    private int age;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return age == user.age && Objects.equals(name, user.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
  • this == o:同一引用直接返回 true,兼顾性能与一致性。
  • getClass() != o.getClass():严格同类比较,子类与父类不算相等(若需要「子类与父类按字段相等」再考虑用 instanceof 等方案)。
  • Objects.equals(name, user.name):避免对 name 做 null 判断,若两者都为 null 也返回 true。

正确重写 hashCode

参与 equals 比较的所有字段都应参与 hashCode 计算,且算法应保持一致。使用 Objects.hash(字段1, 字段2, ...) 即可满足约定且不易出错。

java
@Override
public int hashCode() {
    return Objects.hash(name, age);
}

若类不可变且 hashCode 计算较贵,可考虑缓存哈希值;一般业务类用 Objects.hash 即可。

重写 toString

toString 在打印、日志、调试时被广泛使用。重写后便于阅读,且 IDE 生成的「根据关键字段拼接字符串」的形式通常就够用。

java
@Override
public String toString() {
    return "User{name='" + name + "', age=" + age + "}";
}

提示

使用 IDE 的「生成 equals/hashCode/toString」功能可减少手写错误,生成后可根据业务稍作调整(例如排除某些字段)。


包装类(Wrapper Classes)

与基本类型的对应关系

Java 为每种基本类型提供了对应的包装类,用于在需要「对象」的场合(如集合、泛型)表示该类型的值。

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

自动装箱与自动拆箱

自动装箱:基本类型自动转换为对应包装类对象。自动拆箱:包装类对象自动转换为基本类型。这是编译器提供的语法糖,本质仍是调用 valueOfxxxValue()

java
// 自动装箱:int -> Integer
Integer a = 100;

// 自动拆箱:Integer -> int
int b = a;
int sum = a + 200;   // a 先拆箱再参与运算

// 集合中只能存放对象,泛型中使用包装类
List<Integer> list = new ArrayList<>();
list.add(1);         // 自动装箱
int first = list.get(0);   // 自动拆箱

包装类的常用方法

  • 与字符串互转Integer.parseInt("123")Integer.toString(123),以及带进制或默认值的重载。
  • 比较:包装类应使用 equals 比较内容,不要用 ==== 比较的是引用,缓存范围内可能相等,但不可依赖)。
  • 数值型通用方法:如 Integer.valueOfDouble.valueOf,以及各类型的 xxxValue() 拆箱方法。
java
// 字符串与数值互转
int num = Integer.parseInt("42");
String s = Integer.toString(42);

// 比较:用 equals,不要用 ==
Integer x = 128;
Integer y = 128;
System.out.println(x.equals(y));   // true
System.out.println(x == y);         // false(不同对象)

警告

包装类比较内容时要用 equals,不要用 ==== 比较的是引用,仅当 -128~127 等缓存范围内可能为同一对象,不可作为通用相等判断。

缓存与 valueOf

部分包装类(如 Integer)对一定范围内的值做了缓存,valueOf 可能返回缓存对象,因此同一数值在缓存内可能满足 ==,但代码不应依赖这一实现细节,相等性判断一律用 equals


Math 工具类

Math 提供静态方法用于数学运算,无需创建对象。常用内容如下。

常用方法与常量

  • 取整Math.round(四舍五入)、Math.floor(向下)、Math.ceil(向上)。
  • 最值Math.max(a, b)Math.min(a, b)
  • 幂与开方Math.pow(x, y)Math.sqrt(x)
  • 随机数Math.random() 返回 [0.0, 1.0) 的 double;需要整数范围时可结合乘法和强转,或使用 Random 类。
  • 常量Math.PIMath.E
java
double a = 3.7;
Math.round(a);   // 4
Math.floor(a);   // 3.0
Math.ceil(a);    // 4.0

Math.max(10, 20);   // 20
Math.pow(2, 10);    // 1024.0
Math.sqrt(4);       // 2.0

// [0.0, 1.0) 的随机数
double r = Math.random();
// 例如生成 [1, 100] 的整数(需注意边界)
int rand = (int) (Math.random() * 100) + 1;

信息

需要更灵活或线程安全的随机数时,推荐使用 java.util.RandomThreadLocalRandom(JDK 7+),见 Oracle Java 文档 - Random


注意事项

  1. equals/hashCode:参与 equals 的字段都要参与 hashCode;保持 equals 与 hashCode 一致,且不要依赖对象可变字段在生命周期内的变化来改变 equals 结果,否则在集合中会导致难以排查的 bug。
  2. 包装类:在集合与泛型中必须使用包装类;比较时用 equals,避免用 ==;注意自动拆箱时的 NullPointerException(包装类为 null 时拆箱会抛 NPE)。
  3. Math:方法多为 double 入参和返回值,注意精度与强转;随机数若需整数或特定分布,优先考虑 Random / ThreadLocalRandom

相关链接

基于 VitePress 构建