ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Java学习——常用API Object

2026/9/18 5:30:43 拓冰建站 浏览量
Java学习——常用API Object

在Java中,Object类是所有类的根类,位于java.lang包下。如果一个类没有明确指定继承自哪个类,那么它默认继承自Object类。这意味着Java中的每个类都直接或间接地继承自Object类。因此,Object类定义的方法对所有Java对象都是可用的,这些方法提供了一些基本的行为,如对象的比较、克隆、获取对象的哈希码等。

主要方法

Object类提供了一些重要的方法,这些方法在Java中的所有对象中都可用:

  1. equals(Object obj):比较调用此方法的对象与指定对象是否相等。默认实现是比较对象的内存地址(引用比较)。
  2. hashCode():返回对象的哈希码值,该值用于支持哈希表类的效率,如HashMapHashSet等。默认情况下,是根据对象的内存地址计算得到的。
  3. toString():返回对象的字符串表示。默认实现返回类名加上“@”符号后跟对象的哈希码的无符号十六进制表示。
  4. getClass():获取运行时类的Class对象。Class类的实例表示正在运行的Java应用程序中的类和接口。
  5. clone():创建并返回此对象的一个副本。默认实现是浅复制。
  6. finalize():当垃圾收集器确定不存在对该对象的更多引用时,由垃圾收集器调用此方法。用于释放资源或执行其他清理。
  7. wait()notify()notifyAll():这些方法与对象的监视器相关,用于线程间的协调。

重写equals和hashCode方法

在实际编程中,经常需要根据对象的内容而不是它们的引用来判断对象是否相等。这时,就需要重写equals方法和hashCode方法,以确保基于内容的相等性,并且保持equalshashCode方法之间的一致性(即两个对象通过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;}@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null || getClass() != obj.getClass()) return false;Person person = (Person) obj;return age == person.age && Objects.equals(name, person.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}
}

在Java中,==操作符和equals()方法都用于比较对象,但它们之间有重要的区别:

== 操作符

  • 用途:用于比较基本数据类型和引用类型。
  • 基本数据类型:当用于比较基本数据类型时(如intdoublechar等),==比较的是值是否相等。
  • 引用数据类型:当用于比较引用数据类型(如对象)时,==比较的是两个引用是否指向堆内存中的同一个对象。即,它比较的是对象在内存中的地址。

equals() 方法

  • 用途equals()方法是Object类的一个方法,用于比较两个对象的等价性。默认情况下,Object类的equals()方法和==操作符的行为相同,即比较对象引用。
  • 覆盖equals()方法:通常,类会重写(override)equals()方法以提供逻辑上的等价性比较,例如比较对象的内容是否相同,而不是比较引用。这对于类的实例来说是非常有用的,尤其是在比较如字符串、日期或自定义对象时。

示例

考虑下面的例子,说明==equals()的使用和区别:

String str1 = new String("hello");
String str2 = new String("hello");// 使用 == 操作符比较
System.out.println(str1 == str2); // 输出 false,因为str1和str2引用不同的对象// 使用 equals() 方法比较
System.out.println(str1.equals(str2)); // 输出 true,因为str1和str2的内容相同

在这个例子中,尽管str1str2引用不同的对象(即它们在内存中的地址不同),但它们的内容是相同的。String类重写了Object类的equals()方法,以比较字符串的内容而不是它们的引用。

重要性

正确理解==操作符和equals()方法的区别对于编写正确的Java程序来说非常重要,特别是在涉及对象相等性比较时。务必记住默认情况下equals()方法继承自Object类的实现,可能需要根据你的类的需要重写它。重写equals()时,还应该考虑重写hashCode()方法,以保持equals()hashCode()之间的一致性约定。

Clone

在Java中,clone()方法用于创建并返回调用此方法的对象的一个副本。这个方法是Object类的一个protected方法,这意味着它默认在所有类中都可用,但只能在类的内部或者其子类中被调用。为了在类的外部使用clone()方法,类需要重写clone()方法,并改变其访问级别为public

实现 Cloneable 接口

在Java中,一个对象的clone()方法只能在该对象所属的类实现了Cloneable接口时才能被成功调用。如果调用一个未实现Cloneable接口的对象的clone()方法,将抛出CloneNotSupportedExceptionCloneable接口是一个标记接口,没有包含方法,它的作用是告诉clone()方法可以合法地对该类实例进行字段到字段的复制。

浅拷贝 vs. 深拷贝

  • 浅拷贝(Shallow Copy)clone()方法默认执行的是浅拷贝。在浅拷贝中,对象的非基本数据类型字段仅仅复制引用,而不复制引用的对象本身。因此,原始对象和克隆对象在这些字段上共享引用。
  • 深拷贝(Deep Copy):深拷贝不仅复制对象本身,还复制对象引用的所有对象。这意味着克隆对象和原始对象在所有层次上都是完全独立的。实现深拷贝通常需要重写clone()方法,并在该方法中手动复制所有内部对象。

重写 clone() 方法

为了让一个类可克隆,你需要:

  1. 实现Cloneable接口。
  2. 重写clone()方法,并声明为public
public class Example implements Cloneable {private int[] arr;public Example() {arr = new int[10];// 初始化arr}public int[] getArr() {return arr;}@Overridepublic Object clone() throws CloneNotSupportedException {return super.clone();}
}

示例:深拷贝的实现

public class DeepExample implements Cloneable {private int[] arr;public DeepExample() {arr = new int[10];// 初始化arr}public int[] getArr() {return arr;}@Overridepublic DeepExample clone() throws CloneNotSupportedException {DeepExample cloned = (DeepExample) super.clone();cloned.arr = arr.clone(); // 深拷贝return cloned;}
}

在这个例子中,DeepExample类通过调用数组的clone()方法实现了深拷贝。

注意事项

  • 实现深拷贝可能会很复杂,尤其是当对象图包含多个对象,甚至循环引用时。
  • 使用克隆方法时需要谨慎,因为不当的使用可能导致问题,如意外共享、破坏封装性等。
  • 考虑到克隆的复杂性和潜在问题,有时使用拷贝构造函数或者拷贝工厂方法是更好的选择。

总的来说,clone()方法提供了对象复制的能力,但实现和使用它需要深思熟虑,确保正确处理浅拷贝和深拷贝,以及遵守Cloneable接口的约定。