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

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

package codeTemplate.effectiveJava.bean;

public class PhoneNumber {
    private short areaCode, prefix, lineNum;

    @Override
    public boolean equals(Object obj) {
        //使用==操作符检查“参数是否为这个对象的引用”
        if (obj == this) {
            return true;
        }
        //使用instanceof操作符检查“参数是否为正确的类型”
        if (!(obj instanceof PhoneNumber)) {
            return false;
        }
        //把参数转化为正确的类型
        PhoneNumber phoneNumber = (PhoneNumber) obj;
        //对于该类中的每一个关键域,检查参数中的域是否与该对象中对应的域相匹配
        return phoneNumber.areaCode == this.areaCode && phoneNumber.prefix == this.prefix && phoneNumber.lineNum == this.lineNum;
        //编写完equals方法后,问自己:他是否是对称的,传递的,一致的
    }
}

覆盖equals时一定要覆盖hashCode

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

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

IDE自动生成的方法

package codeTemplate.effectiveJava.bean;

import java.util.Objects;

public class PhoneNumber {
    private short areaCode, prefix, lineNum;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        PhoneNumber that = (PhoneNumber) o;

        if (areaCode != that.areaCode) return false;
        if (prefix != that.prefix) return false;
        return lineNum == that.lineNum;
    }

    @Override
    public int hashCode() {
        int result = areaCode;
        result = 31 * result + (int) prefix;
        result = 31 * result + (int) lineNum;
        return result;
    }
}

始终要覆盖toStri0ng

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

    @Override
    public String toString() {
        return "PhoneNumber{" +
                "areaCode=" + areaCode +
                ", prefix=" + prefix +
                ", lineNum=" + lineNum +
                '}';
    }

谨慎地覆盖clone

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

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

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

package codeTemplate.effectiveJava.bean;

import java.util.Objects;

public class PhoneNumber {
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        PhoneNumber clone = (PhoneNumber) super.clone();
        clone.phoneArea = this.phoneArea;
        return phoneArea;
    }
}

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

拷贝构造器

浅拷贝

public class PhoneNumber {
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;

    PhoneNumber(PhoneNumber phoneNumber) {
        this.areaCode= phoneNumber.areaCode;
        this.prefix= phoneNumber.prefix;
        this.lineNum= phoneNumber.lineNum;
        this.phoneArea= phoneNumber.phoneArea;
    }
}

深拷贝

    PhoneNumber(PhoneNumber phoneNumber) {
        this.areaCode= phoneNumber.areaCode;
        this.prefix= phoneNumber.prefix;
        this.lineNum= phoneNumber.lineNum;
        this.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
    }
package codeTemplate.effectiveJava.bean;

import lombok.Getter;
import lombok.Setter;

@Setter
@Getter
public class PhoneArea {
    private String Country;

    public PhoneArea(String country) {
        Country = country;
    }
}

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

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

拷贝工厂

方法一:

package codeTemplate.effectiveJava.bean;

import java.util.Objects;

public class PhoneNumber {
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;

    public PhoneNumber(PhoneNumber phoneNumber) {
        this.areaCode= phoneNumber.areaCode;
        this.prefix= phoneNumber.prefix;
        this.lineNum= phoneNumber.lineNum;
        this.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
    }

    public static PhoneNumber newInstance(PhoneNumber phoneNumber) {
        return new PhoneNumber(phoneNumber);
    }
}

方法二:

package codeTemplate.effectiveJava.bean;

import java.util.Objects;

public class PhoneNumber {
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;

    public PhoneNumber() {
    }

    public static PhoneNumber newInstance(PhoneNumber phoneNumber) {
        PhoneNumber pn = new PhoneNumber();
        pn.areaCode= phoneNumber.areaCode;
        pn.prefix= phoneNumber.prefix;
        pn.lineNum= phoneNumber.lineNum;
        pn.phoneArea = new PhoneArea(phoneNumber.phoneArea.getCountry());
        return pn;
    }
}

考虑实现Comparable接口

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

package codeTemplate.effectiveJava.bean;

public class PhoneNumber implements Comparable<PhoneNumber>{
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;

    @Override
    public int compareTo(PhoneNumber phoneNumber) {
        int result = Short.compare(areaCode, phoneNumber.areaCode);
        if (result == 0) {
            result = Short.compare(prefix, phoneNumber.prefix);
            if (result == 0) {
                result = Short.compare(lineNum, phoneNumber.lineNum);
            }
        }
        return result;
    }
}

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

package codeTemplate.effectiveJava.bean;

import lombok.Getter;
import lombok.Setter;

import java.util.Comparator;

@Getter
@Setter
public class PhoneNumber {
    private short areaCode, prefix, lineNum;
    private PhoneArea phoneArea;
    private static final Comparator<PhoneNumber> COMPARATOR = Comparator.comparingInt((PhoneNumber pn) -> pn.areaCode)
            .thenComparingInt(pn -> pn.prefix).thenComparingInt(pn -> pn.lineNum);

    public int compareTo(PhoneNumber phoneNumber) {
        return COMPARATOR.compare(this, phoneNumber);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值