Java 常用类之 Object
1、Object 类
Object
类是 Java 中所有类的始祖,我们可以使用 Object 类型的变量引用任何类型的对象。在 Java 中,只有基本类型
不是对象。
注意:数组也是对象,我们可以把它赋值给 Object 类型的变量,也可以通过数组对象调用 Object 类中的方法,如下所示。
public class Main {
public static void main(String[] args) {
int[] arr = new int[10];
Object obj = arr;
System.out.println(arr.equals(new int[10]));
}
}
基本类型由于自动装箱也可以赋值给 Object 类型的变量。
2、equals 方法
Object 类中的 equals
方法比较两个对象的引用
是否相等,源码如下:
public boolean equals(Object obj) {
return (this == obj);
}
而我们通常需要比较两个对象的状态
是否相等,这就需要我们覆盖 Object 类中的 equals 方法。
下面使用 Employee 类举例,给出比较通用的覆盖方法:
class Employee {
private String name;
private double salary;
public Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
@Override
public boolean equals(Object otherObject) {
// 1.判断对象的引用是否相等
if(this == otherObject) return true;
// 2.判断 otherObject 是否为 null
if(otherObject == null) return false;
// 3.判断 this 与 otherObject 的类型是否相等
if(getClass() != otherObject.getClass()) return false;
// 4.将 otherObject 强制类型转换为相应的类型
Employee other = (Employee) otherObject;
// 5.使用 == 比较基本类型,使用 Object.equals 比较引用类型
return Objects.equals(name, other.name)
&& salary == other.salary;
}
}
特别注意
:
- 在第三个判断语句中,两个对象如果类型不同就会返回 false。但是,是否这样实现取决于具体的情况。如果子类判断相等的方式和父类一致,我们可以不强求类型相同,这时使用
if(!(otherObject instanceof Employee)) return false;
语句替换。 - 在最后的 return 语句中,我们比较 name 对象需要使用
Objects.equals
,而不能使用name.equals(other.name)
。这是因为当 name 为 null 时,使用后一种方式会导致空指针异常
。 - 如果在子类中重新定义 equals 方法,我们需要在
return
语句中包含super.equals(other)
调用,来判断父类中的字段是否相同。
补充:对于数组类型的字段,可以使用静态的Arrays.equals
方法判断对应的数组元素是否相等。
3、hashCode 方法
Object 类中的 hashCode
方法是本地方法,它根据对象的存储地址计算得出散列码。
@IntrinsicCandidate
public native int hashCode();
如果我们重新定义了 equals 方法,那么就要为可能插入散列表的对象重新定义 hashCode 方法。且 equals 与 hashCode 的定义必须相容
:如果 x.equals(y) 返回 true,那么 x.hashCode() 就必须与 y.hashCode() 相等。
我们可以使用Objects.hashCode
或Objects.hash
方法为自定义类计算散列码。
补充:对于数组类型的字段,可以使用静态的Arrays.hashCode
方法计算散列码,这个散列码由数组元素的散列码组成。
4、toString 方法
Object 类中的toString
方法返回的是对象的类名和散列码组成的字符串,如下所示:
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
一般而言,我们应该为每个自定义的类覆盖 toString 方法,格式如下:
@Override
public String toString() {
return getClass().getName()
+ "[name=" + name
+ ", salary=" + salary
+ "]";
}
最好通过调用getClass().getName()
获取类名字符串,而不要将类名硬编码到 toString 方法中。这样子类调用父类的 toString 方法时,将会获取子类的类型。
补充:打印一维数组可以使用静态的Arrays.toString
方法,多维数组使用Arrays.deepToString
方法。
5、clone 方法
Object 类中的clone
方法为protected
修饰的本地方法,执行的是浅拷贝,如下所示:
@IntrinsicCandidate
protected native Object clone() throws CloneNotSupportedException;
如果我们想要使用 clone 方法,需要在类上实现Cloneable
接口(该接口是标记接口
),并指定public
修饰符。在方法内部,可以调用 Object 类的 clone 方法执行浅拷贝,也可以自己编写执行深拷贝的代码。
如有错误,欢迎指正。.... .- ...- . .- -. .. -.-. . -.. .- -.-- -.-.--