禁止码迷,布布扣,豌豆代理,码农教程,爱码网等第三方爬虫网站爬取!
所有类的超类
Object 类是 Java 中所有类的超类,Java 中的每个类都是 Object 类的子类。因此可以使用 object 类型的变量引用任何类型的变量,但是 Object 类型的变量只能作为各种值的泛型容器,想要操作该对象还是需要强制类型转换。
Object obj = new Employee("Alice Adams", 75000);
Employee e = (Employee) obj;
在 Java 中基本类型不是对象,而所有数组类型都是基于 Object 类实现的。这点还是很特别的,因为 C++ 没有所有类的根类,而 Python 中的所有数据类型都是对象。
equals 方法
同类判断
equals 方法可以检测一个对象是否等于另一个对象,在 Object 类中的判断方式是判断 2 个对象的引用是否相等。但是在很多情况下我们不关心特们的引用是否相等,而是关系各个状态字段是否相等。因此在基础 equals 方法时,我们经常需要针对状态来进行覆盖。
首先先看看 getClass() 方法,该方法可以返回对象所属的类。使用 getClass() 方法进行判断是可行的,因为当 2 个对象属于同一个类时才有可能相等。接着程序就需要对字段的各状态进行判断:
private String name;
private double salary;
private LocalDate hireDay;
public boolean equals(Object otherObject){
if (this == otherObject) //判断引用是否相等
return true;
if (otherObject == null) //判空
return false;
if (getClass() != otherObject.getClass()) //判断是否是相同的类
return false;
Employee other = (Employee) otherObject; //强制类型转换
return Objects.equals(name, other.name) //比较各个字段值
&& salary == other.salary
&& Objects.equals(hireDay, other.hireDay);
}
当子类覆盖了超类的 equals 方法时,因为超类的 equals 方法可能是私有方法,因此要先调用超类的 equals 方法。
private double bonus;
public boolean equals(Object otherObject){
if (!super.equals(otherObject))
return false;
Manager other = (Manager) otherObject;
return bonus == other.bonus;
}
非同类判断
如果显式参数和隐式参数不是同一个类,equals 使用什么方案判断更为合适?首先先谈一下 instanceof 关键字,它可以测试它左边的对象是否是它右边的类的实例,返回 boolean 的数据类型。
if(!(otherObject instanceof Employee))
return false;
写代码时要怎么选择 instanceof 关键字和 getClass() 方法呢?equals 的设计需要考虑 2 种情形:
- 子类可以有自己的相等性概念,使用 getClass() 方法检测;
- 超类决定相等性概念,选择 instanceof 关键字检测。
equals 方法设计
因此设计一个 equals 方法可以参考以下几点:
- 显式参数命名为 otherObject,比较时用强制类型转换为另一个 other 变量;
- 检测 this 和 otherObject 是否相等;
- 检测 otherObject 是否是 null;
- 比较 this 与 otherObject 的类是否相同;
- 将 otherObject 强制类型转换为相应的类类型变量,比较各个字段。
hashCode 方法
散列码是由对象导出的一个整数值,不同的对象的散列码不同,Object 方法会根据存储地址的不同,为每一个对象提供一个散列码。例如 String 计算散列码的代码:
int hash = 0;
for(int i = 0; i < length(); i++)
hash = 31 * hash + charAt(i);
hashCode 方法定义在 Object,可以返回对象的散列值。当 equals 方法被覆盖时,hashCode 方法也要随之修改,因为 “x.equals(y)” 判断为 true 的 2 个对象,执行 “x.hashCode() == y.hashCode()” 也要为真。当需要组合多个散列值时,使用 Object.hash() 方法是不错的选择。
public int hashCode(){
return Objects.hash(name, salary, hireDay);
}
toString 方法
toString 方法可以返回表示对象值的字符串,常见的表示是“类名+字段值”。例如:
public String toString(){
return getClass().getName()
+ "[name=" + name
+ ",salary=" + salary
+ ",hireDay=" + hireDay + "]";
}
当子类继承超类的 toString 方法时,可以用 super 关键字调用超类的 toString 方法。
public String toString(){
return super.toString() + "[bonus=" + bonus + "]";
}
当对象和一个字符串用 “+” 运算符连接时,toString 方法就会被自动调用。toString 方法可以放映类中各个状态的变化,因此很适合用于调试。
变参方法
注意到我们熟悉的 printf 方法,这个函数能够接收多个参数,它的方法定义如下所示。
public class PrintStream{
public PrintStream printf(String fmt, Object… args){
return format(fmt, args);
}
}
使用 “…” 表示方法可以接受任意数量的对象,而这些对象可以被组织为一个 Object[] 数组来使用。例如这个方法可以比较多个数字的大小:
public static double max(double… values){
double largest = values[0];
for(double v:values){
if(v > largest)
largest = v;
}
return largest;
}
参考资料
《Java 核心技术 卷Ⅰ》,[美]Cay S.Horstmann 著,林琪 苏钰涵 等译,机械工业出版社