一天一个java类——Object【java.lang.Object】

208 阅读5分钟

今天来学习java.lang包下的Object类,

Java Object 类是所有类的父类,也就是说 Java 的所有类都继承了 Object,子类可以使用 Object 的所有方法。

Object 类位于 java.lang 包中,编译时会自动导入,我们创建一个类时,如果没有明确继承一个父类,那么它就会自动继承 Object,成为 Object 的子类。

一般不显示继承,java是如何自动识别的呢?——>一般认为:JDK 6之前是编译器处理,JDK 7之后是虚拟机处理。

Object 类可以显示继承,也可以隐式继承,以下两种方式时一样的:

显示继承:

public class Burns extends Object{

}

隐式继承:

public class Burns {

}

方法如下:

image.png

类的构造函数

Object(): 构造一个新对象

类加载执行的部分

    static {
        registerNatives();
    }

类的方法

1. registerNatives()

private static native void registerNatives();

registerNatives本质上就是一个本地方法,但这又是一个有别于一般本地方法的本地方法,从方法名我们可以猜测该方法应该是用来注册本地方法的。对,你猜的没错。上述代码的功能就是先定义了registerNatives()方法,然后当该类被加载的时候,调用该方法完成对该类中本地方法的注册。这里你可能会有一些疑惑,比如,到底注册了哪些方法?为什么要注册?具体又是怎么注册的?

到底注册了哪些方法?

细心的你可能还会发现,在Object类中,除了有registerNatives这个本地方法之外,还有hashCode()、clone()等本地方法,而在Class类中有forName0()这样的本地方法等等。也就是说,凡是包含registerNatives()本地方法的类,同时也包含了其他本地方法。所以,显然,当包含registerNatives()方法的类被加载的时候,注册的方法就是该类所包含的除了registerNatives()方法以外的所有本地方法

为什么要注册?

一个Java程序要想调用一个本地方法,需要执行两个步骤:第一,通过System.loadLibrary()将包含本地方法实现的动态文件加载进内存;第二,当Java程序需要调用本地方法时,虚拟机在加载的动态文件中定位并链接该本地方法,从而得以执行本地方法。registerNatives()方法的作用就是取代第二步,让程序主动将本地方法链接到调用方,当Java程序需要调用本地方法时就可以直接调用,而不需要虚拟机再去定位并链接

具体怎么注册?

这个问题涉及到registerNatives()的底层C++源码实现,有兴趣可以自行研究

使用registerNatives()方法的三点好处:

  1. 通过registerNatives方法在类被加载的时候就主动将本地方法链接到调用方,比当方法被使用时再由虚拟机来定位和链接更方便有效;
  2. 如果本地方法在程序运行中更新了,可以通过调用registerNative方法进行更新;
  3. Java程序需要调用一个本地应用提供的方法时,因为虚拟机只会检索本地动态库,因而虚拟机是无法定位到本地方法实现的,这个时候就只能使用registerNatives()方法进行主动链接
  4. 通过registerNatives()方法,在定义本地方法实现的时候,可以不遵守JNI命名规范。那什么是JNI命名规范呢?举个例子,我们在Object中定义的本地方法registerNatives,那这个方法对应的本地方法名就叫Java_java_lang_Object_registerNatives,而在System类中定义的registerNatives方法对应的本地方法名叫Java_java_lang_System_registerNatives等等。也就是说,JNI命名规范要求本地方法名由“包名”+“方法名”构成,而上面的例子中,我们将Java中定义的方法名“g”和本地方法名“g_impl”链接了起来,这就是通过registerNatives方法的第四个好处。

参考:blog.csdn.net/Saintyyu/ar…

2、getClass()

public final native Class<?> getClass();

image.png

运行时类就是jvm启动时,加载class文件生成的叫字节码对象,该对象建立后,后续通过创建类对象时,只需要根据字节码对象创建即可,不用每次创建都加载class文件,通过该Class也可以获取类的所有信息(方法,属性),可以说是class文件在虚拟机的快照。许多反射类应用都是基于此

参考:www.cnblogs.com/wsw-bk/p/80…

3、hashCode()

public native int hashCode();

返回对象的哈希代码值:说通俗一点:Java中的hashCode方法就是根据一定的规则将与对象相关的信息(比如对象的存储地址,对象的字段等)映射成一个数值,这个数值称作为散列值。一般应用在hashset,hashtable,hashmap,还有就是一般hashcode和equals方法结果要保持一致,

4、equals(Object obj)

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

Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象,所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的是同一块内存对象,则返回true,如果this和obj指向的不是同一块内存,则返回false,注意:即便是内容完全相等的两块不同的内存对象,也返回false。

java的equals()方法与“==”有什么区别?参考:juejin.cn/post/698087…

5、clone()

protected native Object clone() throws CloneNotSupportedException;

6、toString()

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

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

12、finalize()

protected void finalize() throws Throwable { }