/*
* 08
* 覆盖equals时要遵守通用约定
* 自反性 对称性 传递性 一致性
* */
public class Item08 {
public static void main(String [] arsg){
Item08 i = new Item08();
Item08.Student s = i.new Student();
System.out.println(s.toString());
}
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
class Student{
String name;
int id;
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
private Item08 getOuterType() {
return Item08.this;
}
/* 重载
* public boolean equals(Student obj) {
return false;
}*/
}
}
/*
* 09
* 覆盖equals时总要覆盖hashcode
* 如果不着样做的话,就会违反Object.hashCode的通用约定,从而导致该类无法结合所有基于散列的集合一起正常运作。
*
* 10
* 要始终覆盖toString方法
* 当对象被传递给print,printf,字符串联操作符(‘+’),assert或者被调试器打印出来时,toString会自动调用
* 返回 类名称@散列码的无符号十六进制表示
*
* 11
* 谨慎覆盖clone
*
* 12
* 考虑实现Comparable接口
* 类实现了Comparable接口,就表明它的实例具有内在的排序关系
* java平台类库中得所有值类(value class)都实现了Comparable接口
*
* 如果一个类的compareTo方法方法施加了一个与equals方法不一致的顺序关系,它任然能够正常工作,
* 但是,如果一个有序集合(sorted collection)包含了该类的元素,这个集合就可能无法遵守集合接口(Collection,set,map)的通用约定
* 对于这些接口的通用约定是按照equals方法来定义的,但是有序集合使用了由compareTo方法而不是equals方法所施加的等同性测试
*
* compareTo方法指定了返回值的符号(大于0,小于0,等于0)
* */
public class Item09 {
public static void main(String [] argd){
PhoneNumber pn = new PhoneNumber(123,123,1234);
System.out.println(pn);//类名@散列码的十六进制表示 lu.PhoneNumber@2a139a55 lu.PhoneNumber@99bc1(重写hashcode方法)
Map<PhoneNumber,String> map = new HashMap<PhoneNumber,String>();
map.put(pn, "jjj");
System.out.println(map.get(pn));//jjj
System.out.println(map.get(new PhoneNumber(123,123,1234)));//null jjj(重写hashcode方法后)
/*
* 解释:由于PhoneNumber方法没有覆盖hashCode方法,从而导致两个相等(equals)的实例具有不同的散列码,
* 违反了hashCode的约定,put方法把对象放在一个散列桶中,get方法却从另一个散列桶中查找。即使两个实例正好
* 放在同一个散列桶中,get方法也必定会返回null,因为HashMap有一项优化,可以将与每个项相关联的散列码缓存
* 起来,如果散列码不匹配,也不必验证对象的等同性。
*
* */
}
}
final class PhoneNumber implements Comparable<PhoneNumber>{
private final short areaCode;
private final short prefix;
private final short lineNumber;
public PhoneNumber(int areaCode,int prefix ,int lineNumber){
rangeCheck(areaCode ,999, "areaCode");
rangeCheck(prefix ,999, "prefix");
rangeCheck(lineNumber ,9999, "line number");
this.areaCode=(short)areaCode;
this.prefix=(short)prefix;
this.lineNumber=(short)lineNumber;
}
private static void rangeCheck(int arg,int max,String name){
if(arg < 0 || arg>max)
throw new IllegalArgumentException(name + ":"+arg);
}
@Override
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==this) return true;
if(!(obj instanceof PhoneNumber)) return false;
PhoneNumber pn = (PhoneNumber)obj;
return this.areaCode==pn.areaCode &&
this.lineNumber==pn.lineNumber &&
this.prefix==pn.prefix;
}
/* 重载
* public boolean equals(PhoneNumber obj) {
return false;
}*/
@Override
public String toString() {
// TODO Auto-generated method stub
return super.toString()+"\n"+areaCode+prefix+lineNumber;
}
/*
* 一个好的散列函数:为不同的对象产生不同的散列码
* */
@Override
public int hashCode() {
// TODO Auto-generated method stub
int result=17;
result = 31*result+areaCode;
result = 31*result+prefix;
result = 31*result+lineNumber;
return result;
}
/*
* 报错
* 在未添加泛型时为object
* 注意此参数与equals方法的区别 equals参数必须为Object
@Override
public int compareTo(Object o) {
// TODO Auto-generated method stub
return 0;
}
*/
@Override
public int compareTo(PhoneNumber o) {
// TODO Auto-generated method stub
if(areaCode <o.areaCode) return -1;
if(areaCode >o.areaCode) return 1;
if(prefix < o.prefix ) return -1;
if(prefix > o.prefix ) return 1;
if(lineNumber <o.lineNumber) return -1;
if(lineNumber > o.lineNumber) return 1;
return 0;
}
}
/*
* 12
* 考虑实现Comparable接口
* 类实现了Comparable接口,就表明它的实例具有内在的排序关系
* java平台类库中得所有值类(value class)都实现了Comparable接口
*
* 如果一个类的compareTo方法方法施加了一个与equals方法不一致的顺序关系,它任然能够正常工作,
* 但是,如果一个有序集合(sorted collection)包含了该类的元素,这个集合就可能无法遵守集合接口(Collection,set,map)的通用约定
* 对于这些接口的通用约定是按照equals方法来定义的,但是有序集合使用了由compareTo方法而不是equals方法所施加的等同性测试
*
* compareTo方法指定了返回值的符号(大于0,小于0,等于0)
* */
public class Item12 {
public static void main(String [] args){
Set<String> s = new TreeSet<String>();
s.add("as");s.add("sd");
Collections.addAll(s,args);
System.out.println(s);
System.out.println(Double.compare(13.123, 13.1230000));
System.out.println(Float.compare(13.123f, 13.1230001f));//0
}
}