• Java源码阅读------Object


    描述

    java中一切事物几乎都可以看作类的实例化对象,而所有的类都与Object息息相关,Object类是所有类的父类先祖,甚至是数组arrays都是要实现Object类中定义的方法,如果一个类没有别的继承声明那么这个类一定是继承了Object类。

    相关实现

    常用函数

    equals

    这是比较常用的一个方法,在源码中的实现也很简单。

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

    通过传入的引用和自身比对,如果是对同一个对象的引用返回为真。这里引用是指实例化对象在堆中的地址。

    toString

    这个函数也是比较常用的,是用于对对象进行文字性描述的方法。我们在使用时一般是重载这个方法。

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

    在Object中的直接使用时,返回的是对象运行时的类名与hashCode()获取的表示内存地址信息的值。比如

    Object o=new Object();
    System.out.println(o.toString());
    //输出java.lang.Object@6b884d57
    

    native方法

    在java中有很多的方法不是完全使用java实现的,有些对系统底层的调用还需要使用C语言来实现,对这些函数的声明是用native来声明的。

    registerNatives

    Object类中也有许多的native方法,这些方法在初始化的时候需要将它们与对应的C语言方法对应,而实现这个过程的方法是registerNatives。

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

    在类中对这一方法进行了初始的静态调用,对本地的方法进行注册,在其他类中也用类似的使用,比如System。
    再往深一点看看,就是jni的实现了

    static JNINativeMethod methods[] = {
    {“hashCode”,()I”, 						(void *)&JVM_IHashCode},
    {“wait”,(J)V”, 					(void *)&JVM_MonitorWait},
    {“notify”,()V”, 						(void *)&JVM_MonitorNotify},
    {“notifyAll”,()V”, 						(void *)&JVM_MonitorNotifyAll},
    {“clone”,()Ljava/lang/Object;, 	(void *)&JVM_Clone},
    };
    

    这里是将java中的函数与在C语言中的函数连接,左边是java中的函数名,右边是在C语言中的函数名,中间的像“()I”中的“I”是jni中对数据类型的转换,V是void,I是int,Object对应是Ljava/lang/Object。还有一点是其中并没有getClass这一函数,但是在调用时还是会按这个名称Java_java_lang_Object_getClass调用。
    再看看详细的实现

    JNIEXPORT void JNICALL
    Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
    {
        (*env)->RegisterNatives(env, cls, methods, sizeof(methods)/sizeof(methods[0]));
    }
    //将本地的几个方法methods注册。
    

    hashCode

    public native int hashCode();
    

    使用这一函数对不同的对象进行区分(为不同的对象返回不同的整数(原文)),一般由对象实例化后在堆中的地址转换为整数实现,不是由java自己实现(native)。
    除此之外,该函数为有关哈希表的实现提供支持,比如java.util.HashMap。
    这个函数可以与equals函数呼应,对于equals不相等的函数,使用hashCode得到的是不等的值。(对同一对象的引用,返回的是相等的地址信息,对不同对象的引用返回的是不同的)

    clone

    protected native Object clone() throws CloneNotSupportedException;
    

    这一方法实现了对于已有对象的克隆,但是需要实现Cloneable接口,而且是浅拷贝,具体可以参照Java技巧------Cloneable接口与clone方法

    并发与同步

    synchronized大家应该不陌生,我们通过它来同步某个对象或是代码块,我们称之为锁,锁是干啥的呢?事实上在多线程中往往会出现多个线程对同一对象进行修改,但是我们无法实时更新变量的实际状况,大多数时候在我们刷新数据时,这个数据还在进行变化,最常见的就是买票这一类,因此某一数据在任意时刻仅允许一个线程对其进行更改即拿到了锁(拿到了就锁起来只能自己改),没有拿到的线程就无法进行操作即所谓得阻塞式访问。

    wait(long)

    这个方法有三种种形式,这个是基本的本地实现。

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

    首先,调用这一方法的类已经被线程获取到了锁,正在进行相关的逻辑操作,但是由于设计原因,比如异步操作,一些逻辑需要等待一段时间进行时使用这一方法,使用时正在使用的线程放弃使用解锁等待并让出使用权,直到别的线程调用该类的notify或notifyAll方法或者超过了timeout设置的时间,亦或者其他的线程使用了interrupt()方法,再重新获得锁。参数是指超时时间,如果超时时间为0,则只能等着其他线程通知了。

    wait(long, int)

    这个函数用于更好的去控制超时时间,第二个参数为毫秒量。

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

    特殊情况,超时时间为0。

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

    notify

    通过这一函数来通知等待操作的其他线程,如果有多个线程在等待就选取其中一个。之后,等到正在操作的对象放弃使用权解锁时,该线程运行并获得锁。

    public final native void notify();
    

    notifyAll

    通过这一函数来通知等待操作的其他线程,之后,等到正在操作的对象放弃使用权解锁时,这些线程运行。

    public final native void notifyAll();
    

    强调

    所谓唤醒与获得锁是两个概念,不是说notify就直接可以获得锁并执行,那样notifyAll会存在多个线程同时获得锁。
    被wait的线程要先被唤醒,之后才能参与锁的争夺。
    所以大多数使用是将wait写到循环里,防止判断条件被唤醒的线程打破。

    反射

    java中的反射,即指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性。

    getClass

    public final native Class<?> getClass();
    

    返回这一对象运行时的类Class(这里是指Class这个类)的实例。简单的举个例子。

    Object o=new Object();
    Object s= "123";
    System.out.println(o.getClass().getName());
    System.out.println(s.getClass().getName());
    //输出
    //java.lang.Object
    //java.lang.String
    

    返回的是运行时的类的实例,所以第二个是String,不是Object。

    finalize

    该方法不是什么理解上的析构函数,gc在回收对象之前会调用该函数。我们可以重写该函数实现对象回收前的资源清理。

    protected void finalize() throws Throwable { }
    

    Java无法保证finalize的及时执行,甚至不保证其执行,只是在回收之前调用,除此之外该方法由优先级较低的线程执行,gc至多自动处理一次。

    小结

    Object类还是很重要的,短短的几百行代码(含注释)中蕴含着许多的设计思想,作为众多类的祖先,其中的相关特性值得我们去深究。

  • 相关阅读:
    为什么linux下多线程程序如此消耗虚拟内存【转】
    具体解说Android的图片下载框架UniversialImageLoader之磁盘缓存的扩展(二)
    【leetcode】Longest Common Prefix
    oracle插入特殊字符&#39;&amp;&#39;问题
    tomcat下配置https环境
    .NET--接口设计
    Hibernate知识点总结
    VB.NET中DataGridView控件
    eclipse内存溢出报错:java.lang.OutOfMemoryError:Java heap space
    理论与实际相结合——三层架构解析
  • 原文地址:https://www.cnblogs.com/yanzs/p/13788281.html
Copyright © 2020-2023  润新知