《Effective Java》------对所以对象都通用的方法

版权声明:本文为博主原创文章,转载请注明出处。 https://blog.csdn.net/hanxueyu666/article/details/78631922

尽管Object是一个具体的类,但是设计它主要是为了扩展。它所有的非final方法,equals,hashCode、toString、clone、finlize都有通用的约定

一、覆盖equals时请遵循通用约定

1.1、自反性

对于任何非null的引用值x,x.equals(x)必须返回true

1.2、对称性

对于任何非null的引用值x,y,当且仅当y.equals(x)返回true时。x.equals(y)必须返回true

1.3、传递性

对于任何非null的引用值x,y和z,如果x.equals(y)返回true,并且y.equals(z)也返回true,那么x.equals(z)也必须返回true

1.4、一致性

对于任何的非null引用值x和y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或者一致地返回false

对于任何非null的引用x。x.equals(null)必须返回false

二、覆盖equals时总要覆盖hashCode

在覆盖equals方法中的类中,也必须覆盖hashCode方法。如果不这样做的话,就会违反Object.hashCode的通用约定,从而导致该类结合所有基于散列的集合一起正常运行,这样的集合包括HashMap、HashSet和Hashtable。

相同的对象必须具有相等的散列码
为不相等的对象产生不相等的散列码

散列的简单解决方法

1.把一个非零的常数值,如17,保存在一个名叫result的int变量中;
2.对于equals方法中的关键域产生int类型散列值:
  boolean类型的域(如名叫f)      计算(f?1:0)
   byte,char,short,int类型的域      计算 (int)f
   long类型的域                          计算 (int)(f^(f>>>32))
   float类型的域                          计算 Float.floatToIntBits(f)
   double类型的域                       计算  Double.doubleToLongBits(f)
   引用类型的域                           使用 引用类型的hashCode方法得到的散列值
   数组类型的域                           把数组中的每个元素当成一个关键域,计算出散列值。
3.对于每一个关键域计算出来的散列值 (如名叫c)
   result = result * 31 + c;
最后放回这个result整数   就是计算出来的当前调用hashCode方法得到的散列值。


三、始终覆盖toString

toString约定进一步指出。“”“建议所有的子类都覆盖这个方法”

toString方法应该返回对象中包含的所有值得关注的信息,如果对象很大,包含的状态信息难以用字符串表示,应该返回一个摘要信息。

在实现toString的时候,必须作出是否指定返回值的格式的决定。指定格式的好处是可以被用作一种标准的、明确的、适合人阅读的对象表示法。不足之处在于类一旦指定格式,必须始终如一地坚持这种格式。程序员将编写代码来解析这种字符串,如果将来改变了格式,他们的代码就无法正常运行了。总的来说不指定格式保留了灵活性。


两个建议:
1.无论是否决定指定格式,都应该在文档中明确地表明意图,通过文档注释来说明。
2.无论是否指定格式,都为toString返回值中包含的所有信息,提供一种编程式的访问途径,如使用getter方法提供。否则程序员必须去解析字符串,而这会导致大量不必要的工作量和增加程序出错的可能性。

四、谨慎覆盖clone

这个地方我没太看懂
简而言之,所以实现了Clonable接口的类都应该用一个公有的方法覆盖clone。此公有方法首先调用super.clone,然后修正任何需要修正的域

由于Clonable有很多缺点,有些专家级的程序员干脆从来不去覆盖clone方法,也从来不去调用它,除非拷贝数组。你必须清楚一点,对于一个专门为了继承二设计的类,如果你未能提供行为良好的受保护的clone方法,它的子类就不可能实现clonable接口


五、考虑实现Comparable接口

compareTo方法的通用约定和equals方法的相似,将一个对象与指定对象进行比较。当该对象小于、等于或者大于指定对象的时候,分别返回一个负整数、零或者正整数。如果由于指定对象的类型而无法和该对象进行比较,则抛出ClassCastException异常。
    在下面的说明中,符号sgn(表达式)表示数学中的signum函数,它根据表达式(expression)的值为负值、零和正值,分别返回-1、0、1。
必须确保所有的x和y都满足sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。这也暗示着当且仅当y.compareTo(x)抛出异常时,x.compareTo(y)才抛出异常。这条规则和equals使用规范里面的对称性类似。
必须确保这个比较关系是可传递的:(x.compareTo(y) > 0 && y.compareTo(z) > 0)暗示着x.compareTo(z) > 0也成立。对应着equals使用规范里面的传递性。
必须确保x.compareTo(y) == 0暗示着所有的z都满足sgn(x.compareTo(z)) == sgn(y.compareTo(z))。
强烈建议(x.compareTo(y) == 0) == (x.equals(y)),但是这个并非绝对必要。一般来说,任何实现了Comparable接口的类,若违反了这个条件,都应该明确予以说明。推荐使用这样的说法:“注意,该类具有内在的排序功能,但是与equals不一致”。



猜你喜欢

转载自blog.csdn.net/hanxueyu666/article/details/78631922
今日推荐