zoukankan      html  css  js  c++  java
  • Effective java -- 2 对于所有对象都通用到方法

    第八条:覆盖equals时请遵守通用约定

    什么时候需要覆盖equals方法?类具有自己的逻辑相等概念,并且父类的equals方法不能满足需要。
    重写equals时需要遵循一下约定:

    • 自反性:非null x,x.equals(x)必须是true
    • 对称性:非null x和y,y.equals(x)和x.equals(y)的结果必须一致
    • 传递性:非null x、y、z,如果x.equals(y)和x.equals(z)的结果为true,那么y.equals(z)也必须为true
    • 一致性:非null x、y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)的结果就一致。
    • 对于非null x,x.equals(null)一定是false

    自反性:不知道怎么写能让这个返回false,如果返回false了,那么把结果添加到Collection集合类中时,那么contains方法就会一直返回false
    对称性:

    class Fifth1 {
      private String s;
    
      public Fifth1(String s) {
        this.s = s;
      }
    
      @Override
      public boolean equals(Object o) {
        if (o instanceof Fifth1) {
          return s.equalsIgnoreCase(((Fifth1) o).s);
        }
        if (o instanceof String) {
          return s.equalsIgnoreCase((String) o);
        }
        return false;
      }
    }
        Fifth1 fifth1 = new Fifth1("FZK");
        String s = "fzk";

    这两个比较就违反了自反性,fifth1.equals(s)调用自定义的equals方法,s.equals(fifth1)调用String的equals方法。

        List<Fifth1> list = new ArrayList<Fifth1>();
        list.add(fifth1);
        list.contains(s);

    然后又有这种代码,结果可能是true,也可能抛运行时异常。
    传递性:

    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 obj) {
        if (!(obj instanceof Point))
          return false;
        Point p = (Point) obj;
        return p.x == x && p.y == y;
      }
    }
    
    class ColorPoint extends Point {
      private final String color;
    
      public ColorPoint(int x, int y, String color) {
        super(x, y);
        this.color = color;
      }
    
    }

    ColorPoint肯定需要一个equals。

      @Override
      public boolean equals(Object obj) {
        if (obj instanceof ColorPoint) {
          return false;
        }
        return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
      }
        Point p = new Point(1, 1);
        ColorPoint colorPoint = new ColorPoint(1, 1, "red");

    这两个比较会失去对称性。
    这么写equals:

      @Override
      public boolean equals(Object obj) {
        if (obj instanceof ColorPoint) {
          return false;
        }
        if (!(obj instanceof ColorPoint)) {
          return obj.equals(this);
        }
        // obj is a ColorPoint
        return super.equals(obj) && ((ColorPoint)obj).color.equals(color);
      }

    Point p = new Point(1, 1);
    ColorPoint colorPoint1 = new ColorPoint(1, 1, "red");
    ColorPoint colorPoint2 = new ColorPoint(1, 1, "blue");
    colorPoint1.equals(p);
    colorPoint2.equals(p);
    colorPoint1.equals(colorPoint2);

    比较这三个的时候又会失去传递性。
    其实上面的那种设计,没有什么特别好的办法。改变设计框架还能解决上面的问题,第一中办法是将Color作为ColorPoint的成员。另一种办法是将超类建成抽象类,只要不能直接实例花超类的实例,上面的问题就不会发生。

    一致性:相等的永远相等,除非改变了什么。在比较的时候,不要使equals依赖不可靠的资源。

    非空性:书的作者起的名,指所有的对象和null 比较的时候都不能返回true。还有在方法里不能返回NullpointerException。
    在写完一个equals方法时一定要考虑是否是对称的,传递的,一致的。自反和非空通常会自动满足。

    忠告:

    • 覆盖equals时也要覆盖hashCode()方法。
    • 不要企图让equals过于智能,会出现很多麻烦的东西
    • 不要将生命的Object替换成其他的东西。如果是其他的就是重载而不是覆盖。

    第九条:覆盖equals时总要覆盖hashCode方法

    如果覆盖了equals而没有覆盖hashCode,会违反Object.hashCode的通用约定,导致该类无法结合所有基于散列的集合一起正常运作,这样的集合包括HashMap,HashSet,HashTable。

    Object规范:

    • 在应用的执行期间,只要对象的equals方法的比较所用到的信息没有被修改,那么对这个同一对象调用多次,hashCode方法都返回同一个正数。在同一个应用程序的多次执行过程中,每次执行所返回的正数可以不一致
    • 如果两个对象根据equals比较相等,那么hashCode放回的整数一定相等
    • 如果两个对象根据equals比较不相等,那么hashCode放回的整数有可能相等。但是应该知道,不同对象返回hashCode不相等会提高散列表的性能。

    第十条:始终要覆盖toString方法

    第十一条:谨慎地覆盖clone

    地十二条:考虑实现Comparable

    书中太啰嗦,感觉没什么好说的。

  • 相关阅读:
    MySQL学习-- UNION与UNION ALL
    图解MySQL 内连接、外连接、左连接、右连接、全连接……太多了
    mysql的三种连接方式
    Spring Boot MyBatis配置多种数据库
    @Value注解分类解析
    SpringBoot启动报错Failed to determine a suitable driver class
    idea启动报错:Access denied for user 'root '@'192.168.100.XXX' (using password: YES)
    QStandardItemModel的data线程安全(在插入数据时,临时禁止sizeHint去读model中的data)
    ubuntu 交叉编译qt 5.7 程序到 arm 开发板
    继承QWidget的派生类控件不能设置QSS问题解决(使用style()->drawPrimitive(QStyle::PE_Widget,也就是画一个最简单最原始的QWidget,不要牵扯其它这么多东西)
  • 原文地址:https://www.cnblogs.com/badboyf/p/6283598.html
Copyright © 2011-2022 走看看