• Effective Java学习笔记---------所有对象都通用的方法


    一般不要覆盖equals方法,若一定要覆盖equals,要遵守通用约定

    1. package codeTemplate.effectiveJava.bean;
    2. public class PhoneNumber {
    3. private short areaCode, prefix, lineNum;
    4. @Override
    5. public boolean equals(Object obj) {
    6. //使用==操作符检查“参数是否为这个对象的引用”
    7. if (obj == this) {
    8. return true;
    9. }
    10. //使用instanceof操作符检查“参数是否为正确的类型”
    11. if (!(obj instanceof PhoneNumber)) {
    12. return false;
    13. }
    14. //把参数转化为正确的类型
    15. PhoneNumber phoneNumber = (PhoneNumber) obj;
    16. //对于该类中的每一个关键域,检查参数中的域是否与该对象中对应的域相匹配
    17. return phoneNumber.areaCode == this.areaCode && phoneNumber.prefix == this.prefix && phoneNumber.lineNum == this.lineNum;
    18. //编写完equals方法后,问自己:他是否是对称的,传递的,一致的
    19. }
    20. }

    覆盖equals时一定要覆盖hashCode

    1. @Override
    2. public int hashCode() {
    3. //Object类有一个静态方法,它带有任意数量的对象,并为他们返回一个散列码
    4. return Objects.hash(areaCode, prefix, lineNum);
    5. }

    让IDE生成equals和hashCode方法,通常优于手工实现它们

    IDE自动生成的方法

    1. package codeTemplate.effectiveJava.bean;
    2. import java.util.Objects;
    3. public class PhoneNumber {
    4. private short areaCode, prefix, lineNum;
    5. @Override
    6. public boolean equals(Object o) {
    7. if (this == o) return true;
    8. if (o == null || getClass() != o.getClass()) return false;
    9. PhoneNumber that = (PhoneNumber) o;
    10. if (areaCode != that.areaCode) return false;
    11. if (prefix != that.prefix) return false;
    12. return lineNum == that.lineNum;
    13. }
    14. @Override
    15. public int hashCode() {
    16. int result = areaCode;
    17. result = 31 * result + (int) prefix;
    18. result = 31 * result + (int) lineNum;
    19. return result;
    20. }
    21. }

    始终要覆盖toStri0ng

    使用IDE自动生成,可自己做调整

    1. @Override
    2. public String toString() {
    3. return "PhoneNumber{" +
    4. "areaCode=" + areaCode +
    5. ", prefix=" + prefix +
    6. ", lineNum=" + lineNum +
    7. '}';
    8. }

    谨慎地覆盖clone

    clone方法就是另一个构造器,必须确保它不会伤害到原始的对象,并确保正确地创建被克隆对象中的约束条

    1. @Override
    2. protected Object clone() throws CloneNotSupportedException {
    3. return super.clone();
    4. }

    默认方法,只会克隆基本类型的值,应用类型的引用,自己实现时需要修正任何需要修正的域

    1. package codeTemplate.effectiveJava.bean;
    2. import java.util.Objects;
    3. public class PhoneNumber {
    4. private short areaCode, prefix, lineNum;
    5. private PhoneArea phoneArea;
    6. @Override
    7. protected Object clone() throws CloneNotSupportedException {
    8. PhoneNumber clone = (PhoneNumber) super.clone();
    9. clone.phoneArea = this.phoneArea;
    10. return phoneArea;
    11. }
    12. }

    对象拷贝的更好的方法是提供一个拷贝构造器或拷贝工厂

    拷贝构造器

    浅拷贝

    1. public class PhoneNumber {
    2. private short areaCode, prefix, lineNum;
    3. private PhoneArea phoneArea;
    4. PhoneNumber(PhoneNumber phoneNumber) {
    5. this.areaCode= phoneNumber.areaCode;
    6. this.prefix= phoneNumber.prefix;
    7. this.lineNum= phoneNumber.lineNum;
    8. this.phoneArea= phoneNumber.phoneArea;
    9. }
    10. }

    深拷贝

    1. PhoneNumber(PhoneNumber phoneNumber) {
    2. this.areaCode= phoneNumber.areaCode;
    3. this.prefix= phoneNumber.prefix;
    4. this.lineNum= phoneNumber.lineNum;
    5. this.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
    6. }
    1. package codeTemplate.effectiveJava.bean;
    2. import lombok.Getter;
    3. import lombok.Setter;
    4. @Setter
    5. @Getter
    6. public class PhoneArea {
    7. private String Country;
    8. public PhoneArea(String country) {
    9. Country = country;
    10. }
    11. }

    拷贝构造方法相比于clone方法的优势:

    • 拷贝构造方法实现更简单。不需要实现 Cloneable 接口,也不需要处理 CloneNotSupportedException
    • clone 函数返回一个普通的 Object 类型的引用。还需要转成特定的类型。
    • 在 clone 方法中不能为 final 属性赋值,但是在拷贝构造方法中就可以。

    拷贝工厂

    方法一:

    1. package codeTemplate.effectiveJava.bean;
    2. import java.util.Objects;
    3. public class PhoneNumber {
    4. private short areaCode, prefix, lineNum;
    5. private PhoneArea phoneArea;
    6. public PhoneNumber(PhoneNumber phoneNumber) {
    7. this.areaCode= phoneNumber.areaCode;
    8. this.prefix= phoneNumber.prefix;
    9. this.lineNum= phoneNumber.lineNum;
    10. this.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
    11. }
    12. public static PhoneNumber newInstance(PhoneNumber phoneNumber) {
    13. return new PhoneNumber(phoneNumber);
    14. }
    15. }

    方法二:

    1. package codeTemplate.effectiveJava.bean;
    2. import java.util.Objects;
    3. public class PhoneNumber {
    4. private short areaCode, prefix, lineNum;
    5. private PhoneArea phoneArea;
    6. public PhoneNumber() {
    7. }
    8. public static PhoneNumber newInstance(PhoneNumber phoneNumber) {
    9. PhoneNumber pn = new PhoneNumber();
    10. pn.areaCode= phoneNumber.areaCode;
    11. pn.prefix= phoneNumber.prefix;
    12. pn.lineNum= phoneNumber.lineNum;
    13. pn.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
    14. return pn;
    15. }
    16. }

    考虑实现Comparable接口

    每当实现一个对排序敏感的类时,都应该让这个类实现Comparable接口,以便其实例可以轻松地被分类、搜索、以及用在基于比较的集合中。每当在compareTo方法的实现中比较域值时,都要避免使用<和>操作符,而应该在装箱基本类型的类中使用静态的compare方法,或者在Comparator接口中使用比较器构造方法。

    1. package codeTemplate.effectiveJava.bean;
    2. public class PhoneNumber implements Comparable{
    3. private short areaCode, prefix, lineNum;
    4. private PhoneArea phoneArea;
    5. @Override
    6. public int compareTo(PhoneNumber phoneNumber) {
    7. int result = Short.compare(areaCode, phoneNumber.areaCode);
    8. if (result == 0) {
    9. result = Short.compare(prefix, phoneNumber.prefix);
    10. if (result == 0) {
    11. result = Short.compare(lineNum, phoneNumber.lineNum);
    12. }
    13. }
    14. return result;
    15. }
    16. }

    若没有实现Comparable接口,可以使用一个显式的Comparator来代替

    1. package codeTemplate.effectiveJava.bean;
    2. import lombok.Getter;
    3. import lombok.Setter;
    4. import java.util.Comparator;
    5. @Getter
    6. @Setter
    7. public class PhoneNumber {
    8. private short areaCode, prefix, lineNum;
    9. private PhoneArea phoneArea;
    10. private static final Comparator COMPARATOR = Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
    11. .thenComparingInt(pn -> pn.prefix).thenComparingInt(pn -> pn.lineNum);
    12. public int compareTo(PhoneNumber phoneNumber) {
    13. return COMPARATOR.compare(this, phoneNumber);
    14. }
    15. }

  • 相关阅读:
    【多线程】Thread 类 详解
    详解AUTOSAR:AUTOSAR方法论(理论篇—3)
    前端架构-分层而治,铁打的MV流水的C
    【计算机网络】-性能指标(速率、带宽和吞吐量)
    【LeetCode刷题(数据结构与算法)】:平衡二叉树
    (15)Blender源码分析之闪屏窗口显示菜单功能
    PPT课件培训视频生成系统实现全自动化
    11.25学到的东西==命令行
    CE1到9关详细教程
    Httpd(一)
  • 原文地址:https://blog.csdn.net/jsq916/article/details/126705772