在Java中,经常提到一个词“万物皆对象”,其中的“万物”指的是Java中的所有类,而这些类都是Object类的子类;
Object主要提供了11个方法,大致可以分为六类:
对象比较:
- public native int hashCode(): native方法,用于返回对象的哈希码;
public native int hashCode();
public int hashCode(){
return Objects.hash(name,age);
}
按照约定,相等的对象必须具有相等的哈希码,如果重写了equals方法,就应该重写hashCode方 法,可以使用Objects.hash()来生成哈希码;
- public boolean equals(Object obj): 用于比较2个对象的内存地址是否相等
public boolean equals(Object obj) {
return (this == obj);
}
如果比较的是两个对象的值是否相等,就要重写该方法,比如String类、Integer类等都重写了该方法。举个例子,假如有一个Person类,我们认为只要年龄和名字相同,就是同一个人,那么就可以这样重写equals方法;
class Person1 {
private String name;
private int age;
// 省略 gettter 和 setter 方法
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj instanceof Person1) {
Person1 p = (Person1) obj;
return this.name.equals(p.getName()) && this.age == p.getAge();
}
return false;
}
}
对象拷贝
-
protected native Object clone() throws CloneNotSupportedException
:naitive 方法,返回此对象的一个副本。默认实现浅拷贝,且类必须实现Cloneable接口Object 本身没有实现 Cloneable 接口,所以在不重写 clone 方法的情况下直接直接调用该方法会发生 CloneNotSupportedException 异常。
对象转字符串
-
public String toString()
:返回对象的字符串表示。默认实现返回类名@哈希码的十六进制表示,但通常会被重写以返回更有意义的信息。public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
比如说一个 Person 类,我们可以重写 toString 方法,返回一个有意义的字符串:
public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; }
当然了,这项工作也可以直接交给 IDE,比如 IntelliJ IDEA,直接右键选择 Generate,然后选择 toString 方法,就会自动生成一个 toString 方法。
也可以交给Lombok,使用@Data注解,它会自动生成toString方法;
数组也是一个对象,所以我们通常打印数组的时候,会看到诸如
[I@1b6d3586
这样的字符串,这个就是 int 数组的哈希码。
多线程调度
-
每个对象都可以调用Object的wait/notify方法来实现等待/通知机制,我们可以写一个例子:
public class WaitNotifyDemo { public static void main(String[] args) { Object lock = new Object(); new Thread(() -> { synchronized (lock) { System.out.println("线程1:我要等待"); try { lock.wait(); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("线程1:我被唤醒了"); } }).start(); new Thread(() -> { synchronized (lock) { System.out.println("线程2:我要唤醒"); lock.notify(); System.out.println("线程2:我已经唤醒了"); } }).start(); } }
解释一下:
- 线程 1 先执行,它调用了
lock.wait()
方法,然后进入了等待状态。 - 线程 2 后执行,它调用了
lock.notify()
方法,然后线程 1 被唤醒了。
①、
public final void wait() throws InterruptedException
:调用该方法会导致当前线程等待,直到另一个线程调用此对象的notify()
方法或notifyAll()
方法。②、
public final native void notify()
:唤醒在此对象监视器上等待的单个线程。如果有多个线程等待,选择一个线程被唤醒。③、
public final native void notifyAll()
:唤醒在此对象监视器上等待的所有线程。④、
public final native void wait(long timeout) throws InterruptedException
:等待 timeout 毫秒,如果在 timeout 毫秒内没有被唤醒,会自动唤醒。⑥、
public final void wait(long timeout, int nanos) throws InterruptedException
:更加精确了,等待 timeout 毫秒和 nanos 纳秒,如果在 timeout 毫秒和 nanos 纳秒内没有被唤醒,会自动唤醒。 - 线程 1 先执行,它调用了
反射
-
public final native Class<?> getClass()
:用于获取对象的类信息,如类名。比如说:public class GetClassDemo { public static void main(String[] args) { Person p = new Person(); Class<? extends Person> aClass = p.getClass(); System.out.println(aClass.getName()); } }
输出结果:
com.itwanger.Person
垃圾回收
protected void finalize() throws Throwable
:当垃圾回收器决定回收对象占用的内存时调用此方法。用于清理资源,但 Java 不推荐使用,因为它不可预测且容易导致问题,Java 9 开始已被弃用。