Effective Java(二) 对于所有对象都通用的方法
来源:互联网 发布:ubuntu划分区备份 编辑:程序博客网 时间:2024/05/16 16:05
本章将讲述何时以及如何覆盖这些非final类的Object方法(虽然Comparable.compareTo不是Object方法,因为类似也会涉及)
第8条 覆盖equals时请遵守通用约定
什么时候应该覆盖equals方法呢?
如果类具有自己特有的“逻辑相等”概念(不等同于对象等同),而且超类没有覆盖equals方法以实现期望的行为,这时应该覆盖equals方法。
有一种“值类”不需要覆盖equals方法,即用实例受控确保“每个值至多只存在一个对象”,枚举类型就属于这种。
equals方法的通用约定
自反性: 对于非null x,x.equals(x)
对称性: y.equals(x)—->x.equals(y)
传递性:x.equals(y), y.equals(z)—–>x.equals(z)
一致性:只要x和y的equals参数没有修改,x.equals(y)多次调用,返回值都一致。对于不可变对象,相等的对象永远相等,不相等的对象永远不相等。
“非空性”:对于任何非null的引用值x, x.equals(null) 必须返回false
所有的集合类都依赖于传递给它们的对象遵守equals约定
自反性的反例:
public final class CaseInsensitiveString{ private final String s; public CaseInsensitiveString(String s){ if(s==null){ throw new NullPointerException(); this.s = s; } } @Override public boolean equals(Object o){ if(o instanceof CaseInsensitiveString){ return s.equalsIgnoreCase((CaseInsensitiveString)o) } if(o instanceof String){ return s.equalsIgnoreCase((String)o); } return false; } public static void main(String[] args){ CaseInsensitiveString cis = new CaseInsensitiveString("Polish"); String s = "polish"; cis.equals(s);//返回true s.equals(cis);//返回false }}
传递性的反例:
public class Point{ private final int x; private final int y; public Point(int x, int y){ this.x = x; this.y = y; } @Override pubic boolean equals(Object o){ if(!(o instanceof Point)){ return false; } Point p = (Point)o; return p.x == x && p.y == y; }}public class ColorPoint extends Point{ private final Color color; public ColorPoint(int x, int y, Color color){ super(x, y); this.color = color; } @Override public boolean equals(Object o){ if(!(o instanceof Point)){ return false; } if(!(o instanceof ColorPoint)){ return o.equals(this); } return super.equals(o) && ((ColorPoint)o).color = color; } public static void main(String[] args){ ColorPoint p1 = new ColorPoint(1,2,Color.RED); Point p2 = new Point(1,2); ColorPoint p3 = new ColorPoint(1,2,Color.BLUE); p1.equals(p2)//返回true p2.equals(p3)//返回true p1.equals(p3)//返回false }}
我们无法在扩展可实例化的类的同时,既增加新的值组件,同时又保留equals约定,除非愿意放弃面向对象的抽象所带来的优势。
如果在equals方法中使用getClass代替instanceof,可以扩展可实例化的类和增加新的值组件,同时保留equals约定:
@Overridepublic boolean equals(Object o){ if(o==null||o.getClass()!=getClass()){ return false; } Point p = (Point)o; return p.x == x && p.y == y;}
这种方法只有当对象具有相同实现时,才能使对象等同,但是这在使用多态时可能会出现问题。例如HashSet的contains方法针对ColorPoint将永远返回false.
权宜之计
在ColorPoint中加入一个私有的Point域以及一个公有的视图方法:
public class ColorPoint{ private final Point point; private final Color color; public ColorPoint(int x, int y, Color color){ if(color == null){ throw new NullPointerException(); point = new Point(x, y); this.color = color; } } public Point asPoint(){ return point; } @Override public boolean equals(Object o){ if(!(o instanceof ColorPoint)){ return false; } ColorPoint cp = (ColorPoint) o; return cp.point.equals(point) && cp.color.equals(color); }}
注意,你可以在一个抽象类的子类中增加新的值组件,而不会违反equals约定。
实现高质量equals方法的诀窍:
1. 使用==操作符检查参数是否为这个对象的引用。如果是则返回true,这是一种性能优化,如果比较操作的代价可能很高,就值得这么做。
2. 使用instanceof检查参数是否为正确的类型。
3. 把参数转换为正确的类型。
4. 对于该类的每个关键域,检查参数对象的域是否与之匹配。
域的比较要比简单的等同性测试复杂得多。
域的比较顺序影响equals方法的性能,为了获得最佳性能,应该最先比较最有可能不一致的域,或者开销最低的域。
5. 当你编写了equals方法之后,应该问自己三个问题:是否时对称的、传递的、一致的?
6. 覆盖equals总要覆盖hashCode
7. 不要企图让equals方法过于智能,过度地寻求各种等价关系很容易陷入麻烦之中。
8. 不要讲equals的参数类型Object换成其他类型。
第9条 覆盖equals时总有覆盖hashCode
hashCode的通用约定
1. 只要对用的equals方法的比较操作所用到的信息没有修改,那么对同一对象调用多次hashCode方法返回值必须一致。
2. 相等的对象必须有相等的hashCode
3. 如果两个对象equals返回false,hashCode值不一定要产生不同的结果。但是不同对象产生不同的hashCode有可能提高散列表的性能。
hashCode的计算过程中可以把冗余域(根据其他域可以计算出来的域)排除在外。
必须排除equals方法中没有用到的域
不要试图从hashCode计算中排除一个对象的关键部分来提高性能。
第10条 始终要覆盖toString
(略)
第11条 谨慎地覆盖clone
第12条 考虑实现Comparable接口
- Effective Java(二) 对于所有对象都通用的方法
- Effective Java学习笔记(二)对于所有对象都通用的方法
- 《Effective Java》读书笔记(二)之对于所有对象都通用的方法
- 【effective Java读书笔记】对于所有对象都通用的方法(二)
- Effective Java 读书笔记(二):对于所有对象都通用的方法
- Effective Java:对于所有的对象都通用的方法
- effective java(对于所有对象都通用的方法)
- Effective Java:对于所有对象都通用的方法
- Effective Java Note(对于所有对象都通用的方法)
- Effective Java:对于所有对象都通用的方法
- Effective java笔记-对于所有对象都通用的方法
- Effective Java系列读后感(二)-对于所有对象都通用的方法
- Effective Java读书笔记(第3章-对于所有对象都通用的方法)
- 【读书笔记】《Effective Java》(2)--对于所有对象都通用的方法
- 【effective Java读书笔记】对于所有对象都通用的方法(一)
- 【effective Java读书笔记】对于所有对象都通用的方法(三)
- 对于所有对象都通用的方法(二)
- Effective Java读书笔记(3对于所有对象都通用的方法)
- 图形引擎(三):添加应用程序中的各种组件
- LeetCode进阶之路(Valid Parentheses)
- java基础笔记精简版2
- MySQL数据库Filesort过程
- 7.12 有一行电文,已按下面规律译成密码……
- Effective Java(二) 对于所有对象都通用的方法
- 移动端拖拽的实现效果
- linphone-LinphoneManager.java文件分析
- JavaScript简单例子之DOM动态获取年月日下拉框
- 彻底搞懂Spring类加载(注解方式)
- SQL Server 存储过程
- js 自动补全
- React Native 特定平台选择-Platform
- Java模拟计算器