Object类源码解析
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Object类源码解析相关的知识,希望对你有一定的参考价值。
本文的分析基于JDK 1.8
Java中所有的类都继承自Object类。
Object类的源码解析
1.void registerNatives()
private static native void registerNatives();
static {
registerNatives();
}
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
该方法只是对几个本地方法进行注册(即初始化java方法映射到C的方法)。需要注意的是,很多类中都有这个方法,但是执行注册的目标是不同的。System类中也有该方法,但是它注册的方法是另一些方法。
2.Class <?> getClass()方法
public final native Class<?> getClass();
- 1
- 1
这也是一个本地方法,返回一个对象的运行时类。注意是运行时类。请看下列代码:
public class tests
{
public static void main(String[] args)
{
A te = new B();
System.out.println(te.getClass());
}
}
class A{
}
class B extends A
{
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
运行结果是:
class B
- 1
- 2
- 1
- 2
A类的引用,但是运行时te这个对象的实际类是B。
3.int hashCode()方法
public native int hashCode();
- 1
- 1
这也是一个本地方法,返回值是对象的一个哈希值。
在编写实现hashCode()方法时,我们需要遵守一些约定:
- 在应用程序执行期间,如果一个对象用于equals()方法的属性没有被修改的话,那么要保证对该对象多次返回的hashcode值要相等。
- 如果2个对象通过equals()方法判断的结果为true,那么要保证二者的hashcode值相等。
- 如果2个对象通过equals()方法判断的结果为false,那么对二者hashcode值是否相等并没有明确要求。如果不相等,那么能够提升散列表的性能。
4.boolean equals(Object obj)
public boolean equals(Object obj) {
return (this == obj);
}
- 1
- 2
- 3
- 1
- 2
- 3
从这里我们可以看到,equals(obj)方法最根本的实现就是‘==’,因此对于一些自定义类,如果没有重写hashcode()方法和equals()方法的话,利用‘==’和equals()方法比较的结果是一样的。对于‘==’比较的是地址,equals()方法比较的是内容这种说法,是片面的。(虽然在最常用的String类中是这样的)。
5.Object clone()
protected native Object clone() throws CloneNotSupportedException;
- 1
- 1
这个也是本地方法。需要注意的是该方法是“浅拷贝”的。
- 浅拷贝:如果一个对象内部还有一个引用类型的基本变量,那么再拷贝该对象的时候,只是在通过clone方法新产生的新对象中拷贝一个该基本类型的引用。换句话说,也就是新对象和原对象他们内部都含有一个指向同一对象的引用。
- 深拷贝:拷贝对象的时候,如果对象内部含有一个引用类型类型的变量,那么就会再将该引用类型的变量指向的对象复制一份,然后引用该新对象。
下面2个图可以帮助理解:
6.String toString()方法
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
- 1
- 2
- 3
- 1
- 2
- 3
很简单,就是返回信息而已。该方法经常被重写。
7.final void notify()方法和final void notifyAll()方法
这2个方法都是本地方法,前者唤醒一个在当前对象监视器上等待的线程。后者唤醒所有在当前对象监视器上等待的线程。
我们应该注意的是,这2个方法应当仅仅被拥有对象监视器的线程所调用。而一个线程成为对象的监视器的拥有者有三种方法:
- 执行该对象上的一个同步(synchronized)方法
- 执行一个同步在在对象上的代码块
- 执行该对象的类上的静态同步方法
public final native void notify();
public final native void notifyAll();
- 1
- 2
- 1
- 2
8.final native void wait()方法
本地方法。
首先,调用该方法会抛出中断异常(InterruptedException),调用时应该用try catch捕捉。
public final void wait() throws InterruptedException {
wait(0);//0表示没有时间限制。
}
- 1
- 2
- 3
- 1
- 2
- 3
9.final native void wait(long timeout)
本地方法
该方法也会抛出中断异常,调用时应捕捉。
public final native void wait(long timeout) throws InterruptedException;
- 1
- 1
该方法使当前线程等待,直到另外一个线程调用该对象的notify或notifyAll方法,或者等待时间已到,当前线程才会从等待池移到运行池。
如果在wait之前或者wait的时候,当前线程被中断了,那么直到该线程被恢复的时候才会抛出中断异常(InterruptedException)。
10.final void 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);
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
源码只是将timeout四舍五入,并没有提供更高精度的控制。
11.protected void finalize()方法
垃圾回收器在认为该对象是垃圾对象的时候会调用该方法。子类可以通过重写该方法来达到资源释放的目的。
在方法调用过程中出现的异常会被忽略且方法调用会被终止。
任何对象的该方法只会被调用一次。
总结
- 本地方法有:除了equal()、wait()、wait(long timeout,long nanos)和toString()方法其余均是本地方法。
- equals()方法经常被重写,而在重写的时候,hashcode()方法应当也重写。例如:当用equals()方法判断对象内容一致的时候,如果hashcode()方法没有重写而导致使用该方法得到的哈希值不同,这样就会产生歧义(比如在Set集合中是通过对象的hashcode值来“辨别”对象的,如果对象内容一致,hashcode值却不一致,会在使用Set集合操作时产生歧义)。(其实我感觉这应该就是制定编写hashcode()方法需要遵守那几个规范的原因)
以上是关于Object类源码解析的主要内容,如果未能解决你的问题,请参考以下文章
Android 逆向类加载器 ClassLoader ( 类加载器源码简介 | BaseDexClassLoader | DexClassLoader | PathClassLoader )(代码片段
Android 逆向使用 Python 解析 ELF 文件 ( Capstone 反汇编 ELF 文件中的机器码数据 | 创建反汇编解析器实例对象 | 设置汇编解析器显示细节 )(代码片段