equals()方法与“==”运算符:
1、equals()方法只能比较引用类型,“==”可以比较引用类型及基本类型。
2、“==”进行比较的时候,引用类型数据比较的是引用,即内存地址,基本数据类型比较的是值。(其实比的就是操作数栈中的内容,即大家平时讲的内存地址)
3、默认的equals()方法比较的是内存地址,基本等同于“==”(从Object的源代码可看出)。但对类File、String、Date及包装类来说,是比较的值而不是内存地址
MyEclipse使用(查看API类的源代码,以Object类的equals方法为例)
连按Ctrl+O:第1次是弹出窗口显示当前类的成员变量与成员方法,第2次(第3次)是显示(隐藏)从父类继承的成员信息。
很多我们自己做的类中如果想把属性相等的对象看成相等,也要同样对equals()方法进行覆盖(为确保覆盖,要写成public boolean equals(Object obj)的形式,可从Object类中拷,也可在MyEclipse中自动生成)。
(1)用==检查是否参数就是这个对象的引用
(2)判断要比较的对象是否为null,如果是null,返回false
(3)用instanceof判断参数的类型是否正确
(4)把参数转换成合适的类型
(5)比较对象属性值是不是匹配
另外:如果对象的属性又是一个引用类型的话,要继续调用该引用类型的equals()方法,直到最后得出相同还是不同的结果。
注:覆盖equals应该连带覆盖hashCode方法
哈希值(hashCode)是一个对象的内存地址的散列值,同一个对象的内存地址是相同的,因此它的哈希值也相同。
Java中对hashCode的规定如下:
1)在同一个应用程序执行期间,对同一个对象调用 hashCode(),必须返回相同的整数 结果——前提是equals()所 比较的信息都不曾被改动过。至于同一个应用程序在不同执行期所得的调用结果,无需一致。
2)如果两个对象被equals(Object)方法视为相等,那么对这两个对象调用hashCode()必须获得相同的整数结果。
3)如果两个对象被equals(Object)方法视为不相等,那么对这两个对象调用hashCode()不必产生不同的整数结果。然而程序员应该意识到,对不同对象产生不同的整数结果,有可能提升hashTable(集合框架中的一个类)的效率。
总之,当我们覆盖了equals方法之后,如果不连带覆盖hashCode,那么调用hashCode方法的其它类就不能返回按Java原来设想的那样工作了。如,使用集合对该类对象进行存取操作时就可能会出问题。因为:Set接口及其实现类在集合中有点特殊:它的底层实现方式是MAP;它在存放或读取时都是先按hashCode来查找(本质是判断是否相等),然后再调equals判断相等及做相应操作。因此,如果两个对象的hashCode值不同,则肯定查找不到,因而不可能会执行equals及后续操作。
hashCode是按照一定的算法得到的一个数值,是对象的散列码值。主要用来在集合中实现快速查找等操作,也可以用于对象的比较。
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public class Employee {
private String id;
private String name;
private int salary;
public Employee(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
//把每一个对象的地址映射成一个整数,在对集合或空间的的大小取余得出地址数(如果已存,则存在下一个地址,直到找到存储位置),下次寻找时也是按照这个规律
//alt+shift+s 再加t,myelipes自动生成,选择判断的两个对象是否相等的的决定属性
//注:
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (id == null) {
if (other.id != null)
return false;
} else if (!id.equals(other.id))
return false;
return true;
}
}
public class EqualsDemo {
public static void main(String[] args) {
Person p1=new Person("Jack",20);
Person p2=new Person("Jack",20);
if(p1==p2){
System.out.println("yes");
}else{
System.out.println("no");
}
if(p1.equals(p2)){
System.out.println("yes2");
}else{
System.out.println("no2");
}
System.out.println("==================");
Employee e1=new Employee("1001");
e1.setName("Jack");
e1.setSalary(5000);
Employee e2=new Employee("1001");
e2.setName("Jack");
if(e1.equals(e2)){
System.out.println("yes3");
}else{
System.out.println("no3");
}
System.out.println("=========2==========");
System.out.println(e2);
int n=2;
System.out.println(n);
}
}
toString()方法是Object类中定义的另一个重要方法,其格式为:
public String toString(){……}
方法的返回值是String类型,用于描述当前对象的有关信息。Object类中实现的toString()方法是返回当前对象的类型和内存地址信息,但在一些子类(如String, Date等)中进行了重写,也可以根据需要在用户自定义类型中重写toString()方法,以返回更适用的信息。
除显式调用对象的toString()方法外,在进行String 与其它类型数据的连接操作时,会自动调用toString()方法,其中又分为两种情况:
(1)引用类型数据直接调用其toString()方法转换为String 类型;
(2)基本类型数据先转换为对应的包装类型,再调用该包装类的toString()方法转换为String类型。
如何测试(更改)底层API:
1)测试int是否会被自动先转换成Integer然后输出。
2)更改底层API中Integer类中的toString方法,在其中加入我们的信息输出,观察是否会被执行。
首先拷贝两份份rt文件(一个备份,一个更改)
用360压缩打开src.zip在java中找到lang包,再找Integer.java,复制到当前src文件中
3)更改Integer的源代码,用编译后的.class替换JRE中的对应类文件
打开修改添加信息
用编译后的.class替换JRE中的对应类文件
运行结果: