优雅编程之这样使用对象通用方法,你就“正常”了(三十四)

开心一笑

【一对夫妇避孕失败后生了一个小男孩,孩子一生出来就紧握拳头,一直笑个不停.护士把他的拳头一掰开.发现里面有一把避孕药,接着小男孩开口说话了:“你们两个想弄死我,没那么容易,哈哈哈】

提出问题

项目开发中,对象都通用的方法要注意那些???

解决问题

励志图片
覆盖equals时请遵守通用约定

先温习下枯燥的理论知识,很无聊,但很重要。

  • 自反性:对于任何非null的引用值x,x.equals(x)必须返回true.
  • 对称性:对于非空的引用值x,y,当且仅当x.equals(y)返回true时,y.equals(x)必须返回true.
  • 传递性:对于任何非null的引用值x,y,z,如果x.equals(y)=true,y.equals(z)=true,那么x.equals(z)也必须返回true。
  • 一致性:对于任何非null的引用值x,y,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回true,或一致地返回false.
  • 对于非null的引用值x,x.equals(null)必须返回false.

高质量equals方法的诀窍

  1. 使用==操作符检查参数是否为这个对象的引用。
  2. 使用instanceof操作符检查参数是否为正确的类型。
  3. 把参数转换成正确的类型。
  4. 当编写完成了equals方法之后,应该问自己三个问题,它是否是对称的、传递的、一致的。

我用开发工具自动帮我生成equals方法:

@Override
public boolean equals(Object o) {
    //使用==操作符检查参数是否为这个对象的引用
    if (this == o) return true;
    //使用instanceof操作符检查参数是否为正确的类型
    if (!(o instanceof AyTest)) return false;
    //把参数转换成正确的类型
    AyTest ayTest = (AyTest) o;
    
    if (flowerNum != ayTest.flowerNum) return false;

    return true;
}
覆盖equals时总要覆盖hashCode

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

//这里引用课本的例子,非原创
public final class PhoneNumber {  

    private final short areaCode;        
    private final short prefix;     
    private final short lineNumber;  
      
    public PhoneNumber(int areaCode, int prefix, int lineNumber) {  
        rangeCheck(areaCode, 999,  "area code");  
        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 o) {  
        if (o == this) {  
            return true;  
        }   
        if (!(o instanceof PhoneNumber)) {  
            return false;  
        }    
        PhoneNumber pNumber = (PhoneNumber)o;   
        return (pNumber.lineNumber == lineNumber) && (pNumber.prefix == prefix) && (pNumber.areaCode == areaCode);  
    }  
}  

测试例子:

public static void hashCodePhoneNumber() {  
    Map<PhoneNumber, String> map = new HashMap<PhoneNumber, String>();  
    PhoneNumber phoneNumber = new PhoneNumber(707, 867, 9876);  
    map.put(phoneNumber, "Jenny");
    //这里是重点 重点 重点  一个是new 出来的 一个是 原来的phoneNumber    
    System.out.println(map.get(new PhoneNumber(707, 867, 9876)));  
    System.out.println(map.get(phoneNumber));  
} 

执行结果:

null    
Jenny   

解释一下:

不去覆盖hashCode,使用map.put时,我们是把这些PhoneNumber对象放在各个不同的盒子里,而我们去map.get()的时候,只是去某一个盒子里去找,而如果我们覆盖了hashCode方法,这时,如果通过hashCode计算出来的值是相等的,就会放在同一个盒子里。这样,只要我们对象中保存的值是完全一致的,就会找到这个key所对应的value。

始终要覆盖toString

如果我们不覆盖类的toString()方法,后果可能是当我们需要去打印这个类的对象时,会有一些并非是我们想要的那种结果。现在开发工具很方便,可以使用开发工具自动帮助我们生成。

谨慎的覆盖clone

拷贝的含义是:

  • x.clone() != x
  • x.clone().getClass() == x.getClass()
  • x.clone().equals(x)

覆盖clone方法要非常小心,如果类里面含有复杂数据类型,要进行深度复制,如果类里面有final属性,则无法进行clone,因为final属性在clone时无法再进行赋值。

最好呢就是别去覆盖这个方法,需要复制的话可以使用拷贝构造器和静态拷贝工厂

考虑实现Comparable接口
  • comparaTo方法不是Object中的方法,而是Comparable接口中唯一的方法。该方法不仅可进行等同性比较,还可以进行顺序比较。

  • 接口的通用约定是按照equals方法来定义的,但有序集合使用了compareTo方法的等同性测试。

  • 如果是是一个值类,而且具有明显的内在排序关系,就因该坚决实现该接口。

  • 如果你正在编写一个值类,它具有非常明显的内在排序关系,比如按字母顺序、按数值顺序或者按照年代顺序,那就应该坚决考虑实现这个接口。

参考文章

【1】Effective Java:对于所有对象都通用的方法
【2】Java中equals和==的区别
【3】Effective Java——对所有对象通用的方法
【4】Effective Java 读书笔记之二 对于所有对象都通用的方法
【5】考虑实现Comparable接口

读书感悟

来自韩寒《我所理解的生活》

  • 我所理解的生活就是做着自己喜欢的事情,养活自己,养活家人。生活不是攀爬高山,也不是深潜海沟,它只是在一张标配的床上睡出你的身形。我所理解的生活就是和自己喜欢的一切在一起。
  • 缘分不是走在街上非要撞见,缘分就是睡前醒后彼此想念。
  • 打死也不能放弃,穷死也不能叹气,要让笑话你的人成为笑话。
  • 可以后悔,但不留遗憾,有很多事情做了以后发现自己傻了或者失败了,但还是要去做。
  • 世间万千种宠爱,无数种人心,得之我幸,不得我也没什么不幸。
  • 我相信真诚相待,也相信倒霉认栽。
  • 每个人的道路都不同,我走在我的野路上,她走在她的大路上,都值得祝福。只要不走歪路邪路,每条道路都有成功的方式。

其他

如果有带给你一丝丝小快乐,就让快乐继续传递下去,欢迎转载,点赞,顶,欢迎留下宝贵的意见,多谢支持!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容