Object源码解析

Object类一共有12个方法:

1. registerNatives()

private static native void registerNatives();
    static {
        registerNatives();
    }

registerNatives()是一个native方法,我们可以看出它在static块中被调用,所以Object类一被加载此方法就会被调用。这种类型的方法在java中只需要声明,它的具体实现依靠Java调用外部程序来完成。当我们new一个Object对象时,JVM需要为这个对象在堆内存分配内存空间、定义变量以及产生this指针之类的,而registerNatives()就是来进行对象这一系列初始化操作的。

2. getClass()

public final native Class<?> getClass();

getClass()方法作用返回此Object的运行时类。

3. hasCode()

public native int hashCode();

hashcode()是一个比较奇葩的类,在Object类中,只要重新定义一个Object对象,两者的hashcode值必定不相同,但hashcode方法一旦被重写就必须遵循以下原则:

  • 在Java应用同一次执行过程中,同一个对象被多次调用,它们的hashCode值必须是相同的。而对于同一个应用的两次不同调用,它们的hashCode值可能相同也可能不相同。
    对于两个对象来说,如果它们的equals方法比较返回为true,那么两个对象的hashcode值必然相同。
  • 对于两个对象来说,如果它们的equals()方法返回为false,则它们的hashcode的值可能相等也可能不相等(这就解释了为什么在一些集合类中判断两个对象hashcode后还要使用equals()来进行二次判断,所以当集合类中对象的hashcode不相同的可能性越大,则性能越好,因为就不用在执行equals方法来判断了)。
  • 对于Object对象来说,不同的Object对象的hashcode是不同的,它们返回的是对象的地址,equals返回的也是对象的地址。所以自定义类一般都会重写hashcode()和equal()方法,不然会自动继承Object类中的hashcode()和equals()方法,它们就会通过对象地址来进行判断。

4. equals()

 public boolean equals(Object obj) {
        return (this == obj);
 }

Object类中的equals()跟hashcode()方法一样,比较的是对象的地址,但一般例如String、Integer等都会重写equals方法,如String类中的equals方法为了提高效率首先会使用“ == ”来判断,如果“ == ”判断为真,则直接返回true,如果“”为假,则先要判断两个对象的类型是否相同,如果类型相同则再比较内容。如若创建一个类未特别重写equals方法,则将默认使用Object的equals方法来进行比较,将相当于使用“”来进行比较。

5. clone()

 protected native Object clone() throws CloneNotSupportedException;

Object类中的clone方法采用了protected关键字来进行修饰,其目的是为了避免我们每创建一个类就默认具有clone能力。Object中的clone方法属于浅克隆,它无法实现深拷贝,因为它不知道一个类都有哪些具体的引用类型。浅克隆即拷贝的是对象的引用,而对象的本身没有被拷贝。那么当我们使用clone方法时,将克隆对象和被克隆对象进行“==”比较,我们又会发现结果为false,而equal比较结果为true(非Object类的equals方法),这说明我们使用clone方法克隆出来的对象不是同一个对象,两个对象在堆中具有独立的空间,而此时我们可能会产生疑问为什么会说是clone方法是浅克隆。
深拷贝与浅拷贝图解
实际上浅克隆的说法是相对于对象的属性的而言的。如果对象的属性是基本类型,当然我们就没有必要去考虑浅克隆或者深克隆了,Java默认基本数据类型的克隆是直接复制一份过来,例如上图中Person对象中的age属性,当被克隆对象的age发生改变,不会影响克隆的对象。而对于引用类型而言,浅拷贝是在两个对象之中存在指向同一位置的引用,而深克隆则会在堆内存开辟两个空间,连个对象的引用指向了两个不同的位置。之所以采用protected关键字来避免一个类默认具有浅克隆,就是因为浅克隆具有一定的不安全性。浅克隆由于克隆对象和被克隆对象都指向的同一个地址空间,所以一旦一个对象导致地址空间发生改变,势必会影响另一个对象。
那么我们如何实现深拷贝呢?

  • 重写clone方法 重写clone方法实际上是从在创建一个类时Object类的clone方法不知道该类都有哪些引用类型,所以为了解决这一问题,我们都会改写clone方法,将该类的引用类型都逐层clone来做到深拷贝。
public class People implements Cloneable{

    private Age age;

    public Age getAge() {
        return age;
    }

    public void setAge(Age age) {
        this.age = age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        People str =(People) super.clone();

        str.age = (Age) str.getAge().clone();
        return str;
    }

}
  • 对象序列化 逐层调用clone方法来实现深克隆很明显的问题就是会造成代码量偏大,所以我们一般会采用序列化和反序列化的方式来实现深克隆,被克隆对象的类必须实现Serializable序列化接口。
public class DeepCopyBySerialization {
    public static void main(String[] args) throws IOException, ClassNotFoundException  {
        Age a=new Age(20);
        Student stu1=new Student("摇头耶稣",a,175);
        //通过序列化方法实现深拷贝
        ByteArrayOutputStream bos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(bos);
        oos.writeObject(stu1);
        oos.flush();
        ObjectInputStream ois=new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
        Student stu2=(Student)ois.readObject();
        System.out.println(stu1.toString());
        System.out.println(stu2.toString());
    }
}

6. toString()

  public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }

tostring()方法经常会被复写,用于返回该对象的字符串表示。它将hash值转换为16进制的字符串形式。
7. notify()

   public final native void notify();

唤醒此对象监视器上等待的单个线程。

8. notifyAll()

  public final native void notifyAll();

唤醒此对象监视器上等待的多个线程。
9. wait(long timeout)

   public final native void wait(long timeout) throws InterruptedException;
当前线程阻塞固定时常。

10. wait(long timeout , int nanos)

    public final void wait(long timeout, int nanos) throws InterruptedException {
        if (timeout < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }

        if (nanos > 0) {
            timeout++;
        }

        wait(timeout);
    }
当前线程阻塞固定时常并设定额外值。

11. wait()

   public final void wait() throws InterruptedException {
       wait(0);
   }

当前线程阻塞到调用notify等方法唤醒之前。
12. fianlize()

    protected void finalize() throws Throwable { }

主动释放资源

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值