我们知Object类是Java中所有类的始祖,在Java中每个类都是由他发展而来的,但是却不需这样写:
class Employee extends Object
因为如果没有确切的指出类的超类,Object就会被认为是这个类的超类。根据继承的规则,可以使用Object类型的变量引用任何类的对象:
Object obj = new Student (“lily”,17);
当然,Object类型的变量只能用于作为各种值的通用执行者。要想对其中的内容进行具体操作,还需要清楚对象的原始类型,并进行还原。
Student stu = (Student) obj ;
Object类提供了三个常用的方法:equals ,hashCode ,toString方法,但是超类提供的方法可能并不能满足子类的要求,需要进行方法的复写。
(1)equals方法
Object 类中的equals方法用于检测一个对象是否等于另一个对象。在Object类中,这个方法将判断两个对象是否为相同的引用。如果两个对象具有相同的引用则判断相等。从这点上来看,这点对于Object类的操作来说倒也合情合理,但是对于继承他的大对数类来说可能并不适用。例如,如果两个Student对象,如果他们的姓名,学号一致就认为他们相等。
class Employee
{
....
public boolean equals(Object otherObject)
{
//同一个引用返回真
if (this == otherObject)
return true;
//当对象为null时返回假
if(otherObject == null)
return false;
//如果两个对象不属于同一个类就返回假
if(this.getClass() != otherObject.getClass())//getclass方法用来返回一个对象所属的类
return false;
Employee other = (Employee) otherObject;
//当对象的属性一致时返回真
return Objects.equals(name, other.name) && salary == other.salary &&
Objects.equals(hireDay, other.hireDay);
}
}
在子类中定义equals方法时,首先调用超类的equals方法,如果检测失败则对象就不可能相等,如果超类的域都相等,在根据子类中新添加的域进行检测;
public class Manager extends Employee {
......
public boolean equals(Object otherObject)
{
//super.equals 方法检查otherObject除了bonus属性之外是否相等
if (!super.equals(otherObject))
return false;
Manager manager = (Manager) otherObject;
return bonus ==manager.bonus;
}
}
Java中对于equals方法的要求如下:
1、自反性:对于任何非空引用x,x.equals(x)返回true。
2、对称性: 对于任何引用x和y,当且仅当y.equals(x)返回true,则x.equals(y)也要返回true;
3、 传递性: 对于任何引用x,y,z,如果x.equals(y)返回为ture,y.equals(z)返回为true,则x.equals(z)也应该返回true;
4、一致性:如果x,y没做任何变化,反复调用x.equals(y)应该返回同样的结果。
5、对于任何非空引用x,x.equals(null)都应该返回false;
ps:Java中对于 == 的要求为,等号左右两边为同一引用对象为真。域相等的且不为同一引用为假。
编写一个较为完美的equals方法的步骤如下:
1、显示参数命名为:otherObject,稍后为他转化为另一个叫做other的变量。
2、检测this 与otherObject是否为同一引用:
if (this == otherObject) return true;
3、检测otherObject是否为null,若为null,返回false,
if(otherObject == null) return false;
4、比较this 与otherObject是否同属一类,可通过getClass方法检测,
if(this.getClass() != otherObject.getClass())
return false;
如果所有子类都有统一的语义,就使用instanceof检测:
if(!(otherObject instanceof ClassName)) return false
5、将otherObject转化为相对应的类类型变量
Employee other = (Employee) otherObject;
6、对需要比较的域进行比较。使用 ==进行基本类型的比较,使用equals进行对象域的比较。如果所有的域都匹配,就返回true,否则返回false。
return Objects.equals(name, other.name) && salary == other.salary &&Objects.equals(hireDay, other.hireDay);
(2)hashCode方法
散列码(hash code)是由对象导出的一个整型值。散列码是没有规律的。如果x,y是两个不同的对象,一般来说,x.hashCode()与y.hashCode()的值会不同。由于hashCode定义在Object类中,因此每个对象都有一个默认的散列码,其值为对象的存储地址。
值得注意的是,如果重新定义了equals方法就必须重新定义hashCode方法,以便用户可以将对象插入到散列表中。
hashCode方法应该返回一个整型的数值(可能为负值),并合理的组织实例域的散列码,以便能够让各个不同对象产生的散列码更加均匀。
public int hashCode()
{
//需要组合多个散列值时,可以调用Objects.hash并提供多个参数
return Objects.hash(name, salary, hireDay);
}
equals与hashCode的定义要一致,如果x.equals(y)为true,则x.hashCode()的值就必须要与y.hashCode()的值相等。
(3)toString方法
由于Object类中自带的tostring方法可能并不能满足子类的需求,通常在子类中需要重新定义类的toString方法。
随处可见tostring方法的一个主要原因是,只要对象与一个字符串通过操作符“+”进行操作,Java就会自动调用对象的toString方法。
如果x为一个对象,执行System.out.println(x),就会自动将x转化为x.toString(),并打印出得到的字符串。
public String toString()
{
return "name"+ name+ "salary"+ salary+ "hireDay"+ hireDay;
}
下面程序实现了Employee类和Manager类的equals、hashode、toString方法;
package equals_hashCode_toString;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Objects;
import commonly_class.string;
public class Employee {
private String name;
private double salary;
private Date hireDay;
public Employee(String name, double salary,int year, int month, int day)
{
this.name = name;
this.salary = salary;
GregorianCalendar gregorianCalendar = new GregorianCalendar(year, month-1, day);
hireDay = gregorianCalendar.getTime();
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public Date getHireDay()
{
return hireDay;
}
public void raiseSalary(double byPrecent)
{
double raise = salary * byPrecent /100;
salary = salary + raise;
}
public boolean equals(Object otherObject)
{
//同一个引用返回真
if (this == otherObject)
return true;
//当对象为null时返回假
if(otherObject == null)
return false;
//如果两个对象不属于同一个类就返回假
if(this.getClass() != otherObject.getClass())
return false;
Employee other = (Employee) otherObject;
//当对象的属性一致时返回真
return Objects.equals(name, other.name) && salary == other.salary &&
Objects.equals(hireDay, other.hireDay);
}
public int hashCode()
{
return Objects.hash(name, salary, hireDay);
}
public String toString()
{
return "name"+ name+ "salary"+ salary+ "hireDay"+ hireDay;
}
}
package equals_hashCode_toString;
public class Manager extends Employee {
private double bonus;
public Manager(String name, double salary, int year, int month, int day) {
super(name, salary, year, month, day);
bonus = 0;
}
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus (double bonus)
{
this.bonus = bonus;
}
public boolean equals(Object otherObject)
{
//super.equals 方法检查otherObject除了bonus属性之外是否相等
if (!super.equals(otherObject))
return false;
Manager manager = (Manager) otherObject;
return bonus ==manager.bonus;
}
public int hashCode() {
return super.hashCode()+ 17* new Double(bonus).hashCode();
}
public String toString() {
return super.toString()+"bonus"+ bonus;
}
}
package equals_hashCode_toString;
public class EqualsTest {
public static void main(String[] args) {
Employee Alice1 = new Employee("Alice", 7500, 2016, 10, 17);
Employee Alice2 = Alice1;
Employee Alice3 = new Employee("Alice", 7500, 2016, 10, 17);
Employee Bob = new Employee("Bob", 7500, 2016, 10, 17);
System.out.println("Alice1 == Alice2:" +(Alice1 == Alice2));
System.out.println("Alice1 == Alice3:" +(Alice1 == Alice3));
System.out.println("Alice1.equals(Alice2):" +(Alice1.equals(Alice2)));
System.out.println("Alice1.equals(Alice3):" +(Alice1.equals(Alice3)));
System.out.println("Alice1.hashCode():"+Alice1.hashCode());
System.out.println("Alice2.hashCode():"+Alice2.hashCode());
System.out.println("Alice3.hashCode():"+Alice3.hashCode());
System.out.println("Bob.toString: "+ Bob.toString());
Manager Lily1 = new Manager("Lily", 4000, 2015, 3, 77);
Manager Lily2 = new Manager("Lily", 4000, 2015, 3, 77);
Lily1.setBonus(3500);
System.out.println("Lily1.toString:"+Lily1.toString());
System.out.println("Lily1.equals(Lily2):"+ Lily1.equals(Lily2));
System.out.println("Lily1.hashCode():"+Lily1.hashCode());
System.out.println("Lily2.hashCode():"+Lily2.hashCode());
}
}