每一秒钟的时间都值得铭记

0%

JDK源码-Object类解析

一、JDK源码

作为Java中所有Class的爸爸,Object类无疑是Java中非常重要的一个类,今天我们就直接来阅读以下JDK源码中的Object类,对其中的代码进行解析。

首先,废话不多说,我们直接上源码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package java.lang;

public class Object {

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

public final native Class<?> getClass();

public native int hashCode();

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

protected native Object clone() throws CloneNotSupportedException;

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

public final native void notify();

public final native void notifyAll();

public final native void wait(long timeout) throws 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);
}

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

protected void finalize() throws Throwable { }

}

二、Object类

看到上面的代码,是不是非常惊讶,作为Java中的基类,Object的源码似乎也并不是太复杂。
是的,你没有感觉错误,其实只要你打开JDK的源码来看一看的话,就会发现,在Object类中,除去那些一大堆的看不懂的英文注释之外,所有的有效代码就是上面的那些。
Object类是java.lang包下的一个Class,从写法上来看,它和我们平常自己写的类也没有太大的区别,那么Object类作为java中的基类有什么特殊之处呢,那就让我们来解析一下吧。

1、所有的类都继承自Object类
首先,Object类作为Java的基类,Java中所有的类(包含JDK中的和我们自己定义的)都会显式或隐式继承Object类,所以Object类是Java中所有类的父类,或者是超父类。故此,我们也将Object类称作基类,或者是超类。

2、Object类中的方法
既然Object类是基类,那么根据Java中继承的特性,也就是所Java中除了Object类之外的所有类都是Object类的子类,也就是说Object类中的所有的非私有方法都会被其子类继承。
所以,Java中的任意一个类,都可以调用Object类中的方法。

Object类中的方法一共有13个,1个构造方法,1个私有方法,2个受保护方法,其余9个则是公有方法

而今天需要详细解析的也就是这13个方法。

三、Object中的方法

1、Object()

Object类的构造方法在JDK源码中并没有直接书写出来,是一个默认的无参构造方法,可以直接通过关键字new来进行创建一个Object类型的对象。
例如:

1
Object object = new Object();

2、registerNatives()

1
private static native void registerNatives();

这个方法是private的,是私有的,所以这个方法是Object类独有的方法,不会被其子类继承。
registerNatives() 方法独特的地方在于,使用了 native关键字进行修饰,在java中,使用native关键字进行修饰,那就说明这个方法的底层实现,并不是由Java代码来进行编写的,而是调用了其他语言编写的接口来进行实现的。
我们可以从源码中发现:

1
2
3
static {
registerNatives();
}

在Object类中有一个静态代码块,直接调用了这个方法,也就是说,这个方法是所有的类进行实例化的时候都会执行的方法。
这个方法和Java语言的底层实现有关系,我们只需要了解即可,并不是今天的重点。

3、clone()

1
protected native Object clone() throws CloneNotSupportedException;

clone()方法是一个受保护的方法,作用是克隆一个对象,我们可以实例化一个Object类的对象,看看Object对象可以直接调用哪些方法:
在这里插入图片描述
从上面的图我们可以发现,其实Object类的实例对象竟然也无法调用clone()方法,那么Java中该怎么调用clone()方法呢?
方法很简单,实现Cloneable接口,并覆写clone()方法即可!
我们先来写一个User类,并让User类实现Cloneable接口,并覆写clone()方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class User implements Cloneable{
private Integer id;
private String username;
private String password;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

我们写好了User类,并让User类实现了Cloneable接口和覆写clone()方法,那么我们来实例化一个User对象。
在这里插入图片描述
从上面的图我们可以看见,除去User类自己的6个setter和getter方法之后,User类可以调用的方法有10个,其中就包括之前无法调用的clone()方法。
说完了实现,我们在说说clone方法的结果。

1
2
3
User user1 = new User();
User user2 = (User) user1.clone();
System.out.println(user1 == user2);

执行上面的代码,得到结果:

1
false

从这个结果我们可以看出,其中clone()方法克隆出来的对象,和原来的对象并不是同一个,而是从新创建了一个新的对象。

4、finalize()

1
protected void finalize() throws Throwable { }

finalize()方法是一个和Java的垃圾回收机制有关的方法。
这个方法会在Java的垃圾回收机制回收对象所占内存之前被调用,即当一个对象被Java虚拟机宣告死亡时会先调用它finalize()方法,让这个对象处理它被回收前的最后事情。
如果我们在Java类中覆写了该方法,可以通过覆写的方法,摆脱本身被Java垃圾回收机制回收的命运。
对于这个方法,我们只限于了解,并不深究。

5、getClass()

1
public final native Class<?> getClass();

接下来要说的是9个公有方法,也是Java类中最为常用的9个方法。第一个就是getClass()。
通过这个方法,可以获取Java对象的字节码对象,具体操作如下:

1
2
User user = new User();
Class clazz = user.getClass();

6、hashCode()

1
public native int hashCode();

hashCode()方法,可以获取Java对象的哈希码值,具体操作如下:

1
2
3
User user = new User();
int code = user.hashCode();
System.out.println(code);

运行结果如下:

1
366712642

7、equals(Object obj)

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

equals(Object obj)方法,其实从源码不难发现,equals方法最底层还是调用了==运算符来实现的,也就是说Object类的equals方法和双等号运算符并没有什么区别。
也就是基本数据类型比较值是否相等,应用数据类型比较内存地址是否相等
而String类型的equals方法之所以可以比较应用数据类的值是否相等,那是因为String类中重写了equals方法。

1
2
3
User user1 = new User();
User user2 = user1;
System.out.println(user1 == user2);

结果如下:

1
true

8、toString()

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

toString()方法,在JavaBean中经常被覆写的方法,用于返回对象的字符串表示形式。

1
2
User user = new User();
System.out.println(user.toString());

没有被覆写时结果为:(包名+引用内存地址)

1
com.day01.object.User@15db9742

当toString()方法被覆写时:(字符串形式为自己覆写的toString决定)

1
User [id=null, username=null, password=null]

可以一提的是:

1
System.out.println(user);
1
System.out.println(user.toString());

这个两个书写方式都是一样的,打印一个对象时,默认就是调用该对象的toString()方法。

9、notify()

1
public final native void notify();

唤醒正在等待对象监视器的单个线程。

10、notifyAll()

1
public final native void notifyAll();

唤醒正在等待对象监视器的所有线程。

11、wait()

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

导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法。

12、wait(long timeout)

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

导致当前线程等待,直到另一个线程调用 notify()方法或该对象的 notifyAll()方法,或者指定的时间已过。

13、wait(long timeout, int nanos)

1
2
3
4
5
6
7
8
9
10
11
12
13
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);
}

导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法,或者某些其他线程中断当前线程,或一定量的实时时间。

四、结束

写到这里,Object类的JDK源码也就讲完了。
其实我们可以发现,即便是JDK源码,其实也和我们自己写的代码没有太大的区别,我们完全可以自己阅读JDK源码,理解JDK中各个Java类的具体实现,知道JDK源码中的具体运行原理,这对我们学习Java有很大的帮助。
JDK源码中,有很多的类都是JDK自己封装的Java类,这些类都是由最基础的Java知识衍生而来,万变不离其宗!

坚持原创技术分享,您的支持将鼓励我继续创作!
-------------这是我的底线^_^-------------