JDK1.8源码笔记(1) Object

前言

Object一共包括1个静态方法,11个成员方法。再也不怕面试官问Object了。

All objects, including arrays, implement the methods of this class.
所有的类包括数组类型,都继承了Object类。

静态变量&静态方法

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


定义了一个native的静态方法,并且使用静态代码块进行调用。
和JNI(Java Native Interface)的知识有关。
这个函数的大概作用是用来关联Java方法和C函数的。
https://stackoverflow.com/questions/1010645/what-does-the-registernatives-method-do

成员变量&成员方法

public final native Class<?> getClass();

<?> ?是通配符,似乎是不用强转就可以指向多种类型。

The object that represents the runtime class of this object.
返回类加载到元空间后代表此类的Class对象。
* <p><b>The actual result type is {@code Class<? extends |X|>}
* where {@code |X|} is the erasure of the static type of the
* expression on which {@code getClass} is called.</b> For
* example, no cast is required in this code fragment:</p>
*
* <p>
* {@code Number n = 0; }<br>
* {@code Class<? extends Number> c = n.getClass(); }
* </p>
大意是|X|可以来确定静态类型,不需要进行强制转换。

如果Object对象直接输出的话,可以得到结果class java.lang.Object。

public native int hashCode();
这个方法是很重要的,就像是返回了一个对象的身份证号一样,如果在内存中处于不同的位置,身份证号自然是不相同的。

返回这个对象的hash值,该方法用以给其他方法提供支持,例如java.util.HashMap就是用该方法实现的。

如果在equals方法中用于比较对象的信息没有被修改的话,在一个Java程序的一次执行过程中,同一个对象的该方法返回值应该不变。

Object中的equals方法即return (this == obj)本质上就是比较两个对象的hashCode的值。

这个方法通常是将对象的内部地址转换成整数来实现的,当然Java语言本身不需要实现这个功能,因为这个是native方法。

另外需要注意到返回值是int类型。

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

//Indicates whether some other object is "equal to" this one.

equals方法具有自反性 对称性 传递性 不变性

* Note that it is generally necessary to override the {@code hashCode}
* method whenever this method is overridden, so as to maintain the
* general contract for the {@code hashCode} method, which states
* that equal objects must have equal hash codes.
即使重写equals方法,也应该保证两个相同对象的hash code相同。

下面的调用方式会报空指针异常
//Object obj = null;
//System.out.println(obj.equals(null));

protected native Object clone() throws CloneNotSupportedException;
注意这个方法是protected,其实没什么用,所有类都是Object类的子类。

//Creates and returns a copy of this object.
该方法功能是创建并返回当前对象的一份拷贝。

//The precise meaning of "copy" may depend on the class of the object.
但”复制“的确切含义可能取决于这个对象。

通常的情况下来说,拷贝之后以下语义应该成立。
//x.clone() != x 在内存中不是同一个对象,not equals。
//x.clone().getClass() == x.getClass() 而且是同一个类。

需要注意一点就是,父类和子类使用getClass方法的返回值并不相同,不要搞混了。


* The class {@code Object} does not itself implement the interface
* {@code Cloneable}, so calling the {@code clone} method on an object
* whose class is {@code Object} will result in throwing an
* exception at run time.
Object类本身并没有实现Cloneable接口,所以如果在子类中想要调用clone方法,则必须要实现Cloneable接口,不然会抛出CloneNotSupportedException异常。(只要一个对象自己本身或有一个父类继承Cloneable接口即可)

* Otherwise, this method creates a new instance of the class of this
* object and initializes all its fields with exactly the contents of
* the corresponding fields of this object, as if by assignment; the
* contents of the fields are not themselves cloned.
由上一段内容可以看出,clone默认只是把所有的字段给粘贴过去了,所以基本类型开了新的空间,但引用类型只是把应用给复制过去了。

数组类型是默认实现了Cloneable接口的。数组的拷贝默认也是浅拷贝。

最后我们顺便看一眼Cloneable接口的内容,发现这个接口是空的。
public interface Cloneable {
}

如果想通过clone实现深拷贝的话,就需要在重写clone方法在每一层对象都实现浅拷贝。

例子如下,如果Student类中有Age对象字段。
public Object clone() {
    Student stu = null;
    try {
    stu = (Student)super.clone();//先整体复制
    } catch (CloneNotSupportedException e) {
        e.printStackTrace();
    }
    stu.age = (Age)this.age.clone();//再逐个替换
    return obj;
}

private static final long serialVersionUID = 5195511250079656443L;

最后有一个疑问就是CloneNotSupportedException中的和序列化有关的serialVersionUID有何作用?

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

Returns a string representation of the object.

It is recommended that all subclasses override this method.

这个方法默认返回值类型很清晰,要注意其中是把整数类型的hashCode转换为了十六进制的字符串进行输出。
如果使用System.out.println()直接输出一个对象将会自动调用toString方法。

我明白了,不仅如此,String在输出的时候,应该也是调用了toString方法,只不过toString方法是被重写过了。

public final native void notify();

Wakes up a single thread that is waiting on this object's monitor.

The choice is arbitrary and occurs at the discretion of the implementation.
唤醒谁取决于具体的实现。

The awakened thread will not be able to proceed until the current thread relinquishes the lock on this object.
被唤醒的线程也不过是就绪状态,需要先获得锁才可以执行。


* The awakened thread will
* compete in the usual manner with any other threads that might be
* actively competing to synchronize on this object; for example, the
* awakened thread enjoys no reliable privilege or disadvantage in being
* the next thread to lock this object.
大意是,被唤醒的进程在对锁的争夺上并不会有什么特别的,它还需要正常参与和其他进程对锁的竞争中去。

This method should only be called by a thread that is the owner of this object's monitor.
这个方法应该只有当持有锁的时候才可以调用。
如果没有持有锁而调用这个方法,将会抛出IllegalMonitorStateException异常。

public final native void notifyAll();

Wakes up all threads that are waiting on this object's monitor.

抛出异常的情况同上。

public final native void wait(long timeout) throws InterruptedException;

* Causes the current thread to wait until either another thread invokes the
* {@link java.lang.Object#notify()} method or the
* {@link java.lang.Object#notifyAll()} method for this object, or a
* specified amount of time has elapsed.
使用特定的方法唤醒或超时之后自动唤醒。

* This method causes the current thread (call it <var>T</var>) to
* place itself in the wait set for this object and then to relinquish
* any and all synchronization claims on this object. Thread <var>T</var>
* becomes disabled for thread scheduling purposes and lies dormant
* until one of four things happens:
由于锁是可冲入的缘故,所以提到了可能需要释放多把锁。
....................
* <li>Some other thread {@linkplain Thread#interrupt() interrupts}
* thread <var>T</var>.
interrupt也可以打断wait。
* <li>The specified amount of real time has elapsed, more or less.  If
* {@code timeout} is zero, however, then real time is not taken into
* consideration and the thread simply waits until notified.
如果超时时间设置为0,则会按照一般的wait()进行处理。

* In other words,
* waits should always occur in loops, like this one:
* <pre>
*     synchronized (obj) {
*         while (condition does not hold)
*             obj.wait(timeout);
*         ... // Perform action appropriate to condition
*     }
* </pre>
由于interrupt唤醒和wait唤醒具有很大的不确定性,官方推荐这种方式应该在while循环中使用。
注意if是不行的,必须使用while。
其实上面这种形式实现了一种定时探测的方式,既不会while(true)浪费资源,又可以定时对条件进行判断。
* (For more information on this topic, see Section 3.2.3 in Doug Lea's
* "Concurrent Programming in Java (Second Edition)" (Addison-Wesley,
* 2000), or Item 50 in Joshua Bloch's "Effective Java Programming
* Language Guide" (Addison-Wesley, 2001).
官方推荐啊,哈哈哈哈

对于interrupt的情况,也有特殊说明:
* <p>If the current thread is {@linkplain java.lang.Thread#interrupt()
* interrupted} by any thread before or while it is waiting, then an
* {@code InterruptedException} is thrown.  This exception is not
* thrown until the lock status of this object has been restored as
* described above.
如果该线程在等待之前,或等待期间被另一个线程调用该线程的interrupt()方法,那么当被interrupt线程获得锁之后,会立刻抛出InterruptedException异常,我们可以对这个异常进行捕获,然后处理,以实现线程的唤醒和通信。

* Note that the {@code wait} method, as it places the current thread
* into the wait set for this object, unlocks only this object; any
* other objects on which the current thread may be synchronized remain
* locked while the thread waits.
要注意wait方法是有发生死锁的危险的,如果一个线程同时持有A锁和B锁,并且在A锁上执行了wait方法,则该线程会释放A锁,但并不会主动释放B锁。这是很危险的事情。

once it has gained control of the object, all its
* synchronization claims on the object are restored to the status quo
* ante
如果一旦获得了锁,也随机将会获得之前所加的所有的锁,和释放锁的时候完全对应。

* The current thread must own this object's monitor.
同样,该方法的调用需要先持有锁。

如果timeout为负,会抛出IllegalArgumentException。
如果未持锁非法wait,会抛出IllegalMonitorStateException。
如果线程被别的线程interrupt,再次调度执行的时候会抛出InterruptedException,对这个异常进行捕获即可实现线程间的通信。

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);
}

其实就是骗人的,根本就没有什么毫微秒,如果合法就加1秒而已。

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

其实就是缺省调用了wait(0)。

protected void finalize() throws Throwable { }

Called by the garbage collector on an object when garbage collection determines that there are no more references to the object.

A subclass overrides the {@code finalize} method to dispose of system resources or to perform other cleanup.

重写这个函数的目的一般是为了拯救对象,或者回收资源。

* The Java programming language does not guarantee which thread will
* invoke the {@code finalize} method for any given object. It is
* guaranteed, however, that the thread that invokes finalize will not
* be holding any user-visible synchronization locks when finalize is
* invoked. If an uncaught exception is thrown by the finalize method,
* the exception is ignored and finalization of that object terminates.
Java语言并不保证对于给定的对象,它的finalize方法会由哪个线程调用。
但可以保证调用finalize方法的线程不持有任何用户可见的锁。
如果抛出了没有被捕获的异常,则会被忽略掉,并直接终止该方法。

* The {@code finalize} method is never invoked more than once by a Java
* virtual machine for any given object.

一般只有该方法被重写且没有别调用过才会被执行。
由一个优先级很低的进程负责执行,且不保证一定能执行完这些方法。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值