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
}
}