Effective Java 学习笔记

Effective Java 学习笔记


第三章 对所有方法都通用的方法

equals()

当类为值类(以类中保存的值来区别两个实例)时(枚举例外),需要重写 equals()hashCode() 方法。

重写 equals() 需要遵守的约定:

  1. 非空。x != null
  2. 自反。x.equals(x) == true
  3. 对称。if(x.equals(y)) y.equals(x)
  4. 传递。if(x.equals(y) && y.equals(z)) x.equals(z)
  5. 一致。 只要对象不变,每次调用必须能返回相同的结果。

Tips:

  • 增加值组件时使用复合而不是继承。
public class Point {
    private final int x;
    private final int y;

    public Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || !(o instanceof Point)) {
            return false;
        }

        Point point = (Point) o;
        return x == point.x && y == point.y;
    }

    @Override
    public int hashCode() {
        int result = x;
        result = 31 * result + y;
        return result;
    }
}

public class ColorPoint {
    private final Point point;
    private final Color color;

    public ColorPoint(Point point, Color color) {
        this.point = point;
        this.color = color;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || !(o instanceof ColorPoint)) {
            return false;
        }

        ColorPoint that = (ColorPoint) o;
        if (point != null ? !point.equals(that.point) : that.point != null) {
            return false;
        }
        return color != null ? color.equals(that.color) : that.color == null;
    }

    @Override
    public int hashCode() {
        int result = point != null ? point.hashCode() : 0;
        result = 31 * result + (color != null ? color.hashCode() : 0);
        return result;
    }
}
  • 对于 floatdouble 类型的值进行特殊处理 Float.compare(f1, f2)
  • 域的比较顺序有可能会影响性能,所以应先比较最有可能不同的域及开销最低的域。
  • 总是要覆盖 hashCode() 方法。

hashCode()

约定:

  1. 在应用程序执行过程中,只要 equals() 方法未更改,同一个对象调用 hashCode() 返回结果应该一致。
  2. if(x.equals(y)) x.hashCode() == y.hashCode();

实现约定:

  1. 将一个非 0 常量赋给 result
  2. 计算关键域的 hashCode
    • boolean –> field ? 1 : 0;
    • Byte | char | short | int –> (int)field
    • long –> (int)(field ^ (field >>> 32))
    • float –> Float.floatToIntBits(field)
    • double –> Double.doubleToLongBits(field) –> (long –> int)
    • 对象引用 –> 直接调用 hashCode()
    • 数组 –> Arrays.hashCode();
  3. result = 31 * result + hashCode;
  4. 检验相等实例是否有相同 hashCode。
public class PhoneNumber {
    private final short areaCode;
    private final short prefix;
    private final short lineNumber;

    public PhoneNumber(short areaCode, short prefix, short lineNumber) {
        rangeCheck(areaCode, 999, "area code");
        rangeCheck(prefix, 999, "prefix");
        rangeCheck(lineNumber, 9999, "lineNumber");
        this.areaCode = areaCode;
        this.prefix = prefix;
        this.lineNumber = lineNumber;
    }

    private void rangeCheck(int arg, int max, String name) {
        if(arg < 0 || arg > max){
            new IllegalArgumentException(name + ": " + arg);
        }
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || !(o instanceof PhoneNumber)) {
            return false;
        }

        PhoneNumber that = (PhoneNumber) o;
        return lineNumber == that.lineNumber
                && areaCode == that.areaCode
                && prefix == that.prefix;
    }

    @Override
    public int hashCode() {
        int result = (int) areaCode;
        result = 31 * result + (int) prefix;
        result = 31 * result + (int) lineNumber;
        return result;
    }

    @Override
    public String toString() {
        return "PhoneNumber{" +
                "areaCode=" + areaCode +
                ", prefix=" + prefix +
                ", lineNumber=" + lineNumber +
                '}';
    }
}

Tips:

  1. 删除冗余域。
  2. 计算 hashCode 开销较大时,可以将其缓存到类内部。创建时计算或首次调用 hashCode() 时计算。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值