【Effective Java 10.2】覆盖 equals 时请遵守通用约定 —— 对称性

2022/3/28 22:22:36

本文主要是介绍【Effective Java 10.2】覆盖 equals 时请遵守通用约定 —— 对称性,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

任何两个对象对于 “它们是否相等” 问题必须保持一致。与第一个要求不同,若无意中违反这一条,这种情形倒是不难想象。例如,下面的类,它实现了一个不区分大小写的字符串。字符串由 toString 保存,但在 equals 操作中被忽略。

/**
 * 覆写 Object 的 equals 方法时, 必须满足对称性要求 (Symmetry)
 * 即 x.equals(y) 与 y.equals(x) 的行为必须一致
 * <p>
 * 下面展示了一个违反该约定的情况
 * 一旦违反了 equals 约定, 当其他对象面对你的对象时, 你完全不知道这些对象的行为会怎样.
 */
public class SymmetryBadDemo {
    public static final class CaseInsensitiveString {
        private final String s;

        public CaseInsensitiveString(String s) {
            this.s = s;
        }

        /**
         * 这里的 equals 方法存在一个漏洞
         * 就是一个 CaseInsensitiveString 对象和一个 String 对象比较的时候会出现问题
         * 造成这一现象的原因主要是
         */
        @Override
        public boolean equals(Object o) {
            if (o instanceof CaseInsensitiveString) {
                return s.equalsIgnoreCase(((CaseInsensitiveString) o).s);
            }
            if (o instanceof String) {
                return s.equalsIgnoreCase(((String) o));
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(s.toLowerCase());
        }
    }

    public static void main(String[] args) {
        CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
        String s = "polish";
        System.out.println("违反自反性的例子");
        System.out.println("cis.equals(s) = " + cis.equals(s));
        System.out.println("s.equals(cis) = " + s.equals(cis));
    }
}

为了解决这个问题,是需要禁止 StringCaseInsensitiveString 之间的互操作即可。

public class SymmetryGoodDemo {

    public static final class CaseInsensitiveString {
        private final String s;

        public CaseInsensitiveString(String s) {
            this.s = s;
        }


        /**
         * 解决方法: 禁止与 String 类型的对象互操作
         * 由于 CaseInsensitiveString 与 String 之间没有任何继承关系.
         * 而 equals 函数输入的是一个 Object 对象
         * 要避免 CaseInsensitiveString 与 String 之间进行比较
         * 就要在 equals 中主动判断 Object 对象的实际类型与当前类的类型是否一致
         */
        @Override
        public boolean equals(Object o) {
            return o instanceof CaseInsensitiveString && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
        }

        @Override
        public int hashCode() {
            return Objects.hash(s.toLowerCase());
        }
    }

    public static void main(String[] args) {
        CaseInsensitiveString cis = new CaseInsensitiveString("Polish");
        String s = "polish";
        System.out.println("遵守自反性的修改");
        System.out.println("cis.equals(s) = " + cis.equals(s));
        System.out.println("s.equals(cis) = " + s.equals(cis));
    }
}


这篇关于【Effective Java 10.2】覆盖 equals 时请遵守通用约定 —— 对称性的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程