day11 equals和hashCode方法重写

equals和hashCode方法重写

1.重写equals

==和equals的区别?

==比较基本数据类型 比较值

==比较引用数据类型 比较地址

equals底层依然使用==比较地址 但是我们可以重写自定义比较规则

String类就是对equals方法进行了重写 将原本的比较地址 修改为比较地址 + 比较内容

Person类中重写equals方法原因:在现实生活中,如果有"两个人"名字和身份证号都相同

那么就是同一个人 所以我们应该让这样的两个人(Person)对象 equals比较为true

重写equals方法:按照名字和身份证号比较 不再只根据地址比较

package com.atguigu.test1;
/**
 * ==和equals的区别?
 * ==比较基本数据类型 比较值
 * ==比较引用数据类型 比较地址
 * equals底层依然使用==比较地址 但是我们可以重写自定义比较规则
 * String类就是对equals方法进行了重写 将原本的比价地址 修改为比较地址 + 比较内容
 *
 * Person类中重写equals方法原因:在现实生活中,如果有两个人名字和身份证号都相同
 * 那么就是同一个人 所以我们应该让这样的两个人(Person)对象 equals比较为true
 *
 * 重写equals方法:按照名字和身份证号比较 不再只根据地址比较
 * */
public class Person {

    private String name;
    private String idCard;

    public String getName(){
        return name;
    }

    public void setName(String name){
        this.name = name;
    }

    public String getIdCard(){
        return idCard;
    }

    public void setIdCard(String idCard){
        this.idCard = idCard;
    }

    public Person(){

    }

    public Person(String name, String idCard){
        this.name = name;
        this.idCard = idCard;
    }

    public boolean equals(Object obj){
        if (this == obj){
            return true;
        }
        // 代码执行到这里 表示两个对象地址不同 哦我们接下来就按照名字和身份证号来比较
        Person p = (Person)obj;
        if (this.name.equals(p.name) && this.idCard.equals(p.idCard)){
            return true;
        }
        return false;
    }

    public static void main(String[] args) {
        String str1 = new String("abc");  // false
        String str2 = new String("abc");  // true
        System.out.println(str1 == str2);  // 比较地址
        System.out.println(str1.equals(str2));
        System.out.println("-----------------------------------");

        Person p1 = new Person("赵四", "1232343534534525424");
        Person p2 = new Person("赵四", "1232343534534525424");

        System.out.println(p1 == p2);  // false
        System.out.println(p1.equals(p2));  // true

        double d1 = 2.5;
        int i1 = (int)d1;
        System.out.println(i1);  // 2
    }
}

2. 类类型的属性&类类型数组

我们在描述某个信息,无法使用基本数据类型或者String,数组等类型描述的情况,可以自定义数据类型来实现

我们自己写的类,就是自定义的数据类型

对象关系:

学生—地址 : 属于一对一关系

学生—爱好: 属于一对多关系

爱好—学生: 属于多对一关系

多个学生—多个爱好: 属于多对多关系

使用指向为null的引用调用任何的属性、方法都会出现空指针异常

package com.atguigu.test3;
/**
 * 学术类
 *      名字
 *      年龄
 *      地址
 *      爱好
 *      
 * */
public class Student {
    private String name;
    private int age;
    private Address address;
    private Hobby[] hobbies;  // 每个学生可以有多个爱好 所以使用爱好类型的数组表示

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    public Hobby[] getHobbies() {
        return hobbies;
    }

    public void setHobbies(Hobby[] hobbies) {
        this.hobbies = hobbies;
    }
}

package com.atguigu.test3;
/**
 * 地址类
 * */
public class Address {
    private String province;
    private String city;
    private String area;
    private String street;
    private String zipCode;
    private String phone;

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getZipCode() {
        return zipCode;
    }

    public void setZipCode(String zipCode) {
        this.zipCode = zipCode;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    @Override
    public String toString() {
        return "Address{" +
                "province='" + province + '\'' +
                ", city='" + city + '\'' +
                ", area='" + area + '\'' +
                ", street='" + street + '\'' +
                ", zipCode='" + zipCode + '\'' +
                ", phone='" + phone + '\'' +
                '}';
    }
}

package com.atguigu.test3;
/**
 * 爱好类
 *      爱好类型
 *      爱好名称
 * */
public class Hobby {
    private String hobbyType;
    private String hobbyName;

    public String getHobbyType() {
        return hobbyType;
    }

    public void setHobbyType(String hobbyType) {
        this.hobbyType = hobbyType;
    }

    public String getHobbyName() {
        return hobbyName;
    }

    public void setHobbyName(String hobbyName) {
        this.hobbyName = hobbyName;
    }

    @Override
    public String toString() {
        return "Hobby{" +
                "hobbyType='" + hobbyType + '\'' +
                ", hobbyName='" + hobbyName + '\'' +
                '}';
    }
}

package com.atguigu.test3;

import java.util.Arrays;

public class TestStudent {
    public static void main(String[] args) {
        Student stu1 = new Student();

        stu1.setName("赵四");
        stu1.setAge(20);

        Address addr1 = new Address();

        addr1.setProvince("广东省");
        addr1.setCity("深圳市");
        addr1.setArea("龙岗区");
        addr1.setStreet("布吉街道");
        addr1.setZipCode("324234");
        addr1.setPhone("2131432543453");

        stu1.setAddress(addr1);

        System.out.println("-------------------------");

        System.out.println(stu1.getName());
        System.out.println(stu1.getAge());

        System.out.println(stu1.getAddress());
        System.out.println(stu1.getAddress().toString());

        System.out.println("-------------------------");

        System.out.println(stu1.getAddress().getProvince());
        System.out.println(stu1.getAddress().getCity());
        System.out.println(stu1.getAddress().getArea());
        System.out.println(stu1.getAddress().getStreet());
        System.out.println(stu1.getAddress().getZipCode());
        System.out.println(stu1.getAddress().getPhone());

        System.out.println("-------------------------");

        Hobby[] hobbies = new Hobby[3];  // 创建三个hobby对象的数组, 此时三个对象的默认值为null

        hobbies[0] = new Hobby();  // 必须先new对象 开辟空间 才能给属性赋值
        hobbies[0].setHobbyType("体育");
        hobbies[0].setHobbyName("篮球");

        hobbies[1] = new Hobby();  // 如果这一行new对象不写 直接调用set方法赋值 将报空指针异常
        hobbies[1].setHobbyType("文艺");  // 使用指向为null的引用调用任何的属性、方法都会出现空指针异常
        hobbies[1].setHobbyName("唱、跳、rap");

        hobbies[2] = new Hobby();
        hobbies[2].setHobbyType("电子竞技");
        hobbies[2].setHobbyName("LOL");

        stu1.setHobbies(hobbies);


        for (int i = 0;i < hobbies.length;i++){
            System.out.println(hobbies[i]);  // Hobby类没重写toString前 输出地址值  重写后则输出属性名和属性值
        }

        System.out.println("------------------------");

        System.out.println(Arrays.toString(stu1.getHobbies()));  // [Hobby{hobbyType='体育', hobbyName='篮球'}, Hobby{hobbyType='文艺', hobbyName='唱、跳、rap'}, Hobby{hobbyType='电子竞技', hobbyName='LOL'}]
    }
}

3. 重写hashCode

重写hashCode方法

什么是hashCode?

hash(杂乱 杂凑) 是一个int类型数值

根据地址等杂乱的条件(杂凑算法)所计算出来的整数数值

为什么要重写hashCode?

1.实际开发中 equals方法 和 hashCode方法是绑定在一起的 两个方法会一起重写

2.默认情况下 equals方法比较为true 那么两个对象的hash值也是相同的

但是目前我们重写了equals方法 改变了比较规则 equals比较为true 但是hashCode却不同

所以我们要重写hashCode方法 继续维持这个规则

3.在散列数据结构中 是以equals比较为true 并且hashCode相同作为去除重复元素的依据

为什么计算hashCode使用 31 ?

31是一个特殊的质数 任何数乘以31 等同于 这个数左移5位 减去这个数本身

n * 31 = (n << 5) - n

总结:使用31计算hashCode 效率高

package com.atguigu.test5;

import java.util.Objects;

/**
 * 重写hashCode方法
 *
 * 什么是hashCode?
 *      hash(杂乱 杂凑) 是一个int类型数值
 *      根据地址等杂乱的条件(杂凑算法)所计算出的整数数值
 *
 * 为什么要重写hashCode?
 *      1.实际开发中equals方法 和 hashCode方法是绑定在一起的 两个方法会一起重写
 *      2.默认情况下 equals方法比较为true 那么两个对象的hash值也是相同的
 *      但是目前我们重写了equals方法 改变了比较规则 equals比较为true 但是hashCode却不同
 *      所以我们要重写hashCode方法 继续维持这个规则
 *      3.在散列数据结构中 是以equals比较为true 并且hashCode相同作为去除重复元素的依据
 * */
public class Person {
    private String name;
    private String idCard;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getIdCard() {
        return idCard;
    }

    public void setIdCard(String idCard) {
        this.idCard = idCard;
    }

    public Person() {
    }

    public Person(String name, String idCard) {
        this.name = name;
        this.idCard = idCard;
    }

//    // 手动重写equals方法
//    public boolean equals(Object obj){
//        if (this == obj){  // 如果地址相同 则返回true
//            return true;
//        }
//        // 代码执行到这里 表示两个对象地址不同 我们接下来就按照名字和身份证号来比较
//        Person p = (Person)obj;
//
//        if (this.name.equals(p.name)  && this.idCard.equals(p.idCard)){
//            return true;
//        }
//        return false;
//    }
//
//    // 手动重写hashCode方法
//    public int hashCode(){
//        int prime = 31;  // 权重
//        int result = 1;
//
//        result = prime * result + (this.name == null ? 0 : this.name.hashCode());
//        result = prime * result + (this.idCard == null ? 0 : this.idCard.hashCode());
//        return result;
//    }


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return Objects.equals(name, person.name) &&
                Objects.equals(idCard, person.idCard);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, idCard);
    }
}

package com.atguigu.test5;

public class TestPerson {
    public static void main(String[] args) {
        Person p1 = new Person("张三", "1231312342341242341234");
        Person p2 = new Person("张三", "1231312342341242341234");

        System.out.println(p1.equals(p2));

        // 重写hashCode方法前打印
//        System.out.println(p1.hashCode());  // 356573597
//        System.out.println(p2.hashCode());  // 1735600054

        System.out.println("--------------------------");

        // 重写hashCode方法后打印
        System.out.println(p1.hashCode());  // 102835511
        System.out.println(p2.hashCode());  // 102835511

        System.out.println("--------------------------");

        // String类重写了equals方法 将Object父类中原本比较地址改变为了比较内容
        // 同时重写了hashCode方法 重写为也根据内容计算hashCode
        // 这样做的目的在于 保证 equals比较为true的情况 hashCode也相同

        String str1 = new String("abc");
        String str2 = new String("abc");

        System.out.println(str1.equals(str2));  // true
        System.out.println(str1.hashCode());  // 96354
        System.out.println(str2.hashCode());  // 96354
    }
}

package com.atguigu.test5;

/**
 * 为什么计算hashCode使用31?
 *      31是一个特殊的质数 任何数乘以31 等同于 这个数左移5位 减去这个数本身
 *      n * 31 = (n << 5) - n
 *      总结:使用31计算hashCode 效率高
 * */
public class TestPrime {
    public static void main(String[] args) {
        System.out.println(2 * 31);  // 62
        System.out.println((2 << 5) - 2);  // 62

        System.out.println(22 * 31);  // 682
        System.out.println((22 << 5) - 22);  // 682
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值