java基础--Object源码学习笔记

一、简介

Object类是Java类继承的顶层。所有类继承自Object,包括Arrays的很多
类、都需要实现Object的方法。

 

二、方法分析

总览:


1、构造方法

类没有给出构造方法,所以构造方法是默认的无参构造方法。

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

registerNatives(),本地静态方法,静态代码块中被调用,随着类的加载被加载进内存,那该方法作用是什么,首先要搞清楚什么是本地方法。

本地方法:在jdk中,jdk源码主要是由c++,java,c,汇编语言组成的,java中存在java方法和本地方法,java方法是由java编写,编译成字节码文件,存储在class文件中。本地方法定义用native修饰,只有定义,没有实现,但和抽象方法不同,也无法和abstract连用,本地方法是由其他语言编写实现,编译成机器代码,保存在动态链接库中,所有虚拟机装载包含本地方法的动态库。

除此之外,本地方法其实和一般方法并无太太区别,可以被调用,被static,final等关键字修饰,可以被继承,被重写。那为什么需要存在本地方法?

   事实上,本地方法作用很大,他有效第拓展了jvm,使得java程序能够超越java运行的界限。列如,在和java外部环境交互时,当需要和操作系统底层硬件交换信息时,利用本地方法提供的接口,使得我们不必了解java之外细节。

有关本地方法参考   https://blog.csdn.net/wike163/article/details/6635321

再说到registerNatives方法,该方法本身是一个本地方法,但又区别于一般本地方法,它主要是对类中所有本地方法注册。一个java方法想要调用一个本地方法,需要将包含本地方法实现的动态文件加载进内存,虚拟机在加载的动态文件中定位链接该本地方法,再执行。registerNatives方法就是执行第二步,方便高效。

 

3、public final native Class<?> getClass();

返回类的一个对象引用,,在同一个类型多个对象调用这个方法,返回同一个类对象引用。被final修饰,不可被继承,重写。

        Class<? extends MyObject> aClass = new MyObject().getClass();
        Class<? extends MyObject> aClass1= new MyObject().getClass();
        System.out.println(aClass);     //class YuanMa.MyObject
        System.out.println(aClass.equals(aClass1)); //true

4、public native int hashCode();  

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

返回对象的哈希码值,具体的实现是对象在内存的地址通过特定方法转换为数字。同一个对象的哈希码值一定相等,不同对象的哈希码值可能相等。

在object里,equals方法用于比较对象,比较的是对象的地址,若不重写equals方法,其和“==”无异。

方法特性:

(1)自反性,x.equals(x)=true;

(2)对称性,x.equals(y) = y.equals(x);

(3)传递性,若x.equals(y) = true,y.equals(z) = true,则x.equals(z) = true;

(4)一致性,只要equals的比较操作在对象中所用的信息没有被修改,多次调用x.equals(y)就会一致地返回相同结果;

(5)x.equals(null) = false;

在对象重写equals方法,也应该重写hashcode方法,对象比较时,通过先比较hashcode值,如果相同在调用equals方法,如果不同,两个对象必定不同,性能更叫高效。

 

5、protected native Object clone() throws CloneNotSupportedException;

克隆方法,对象的克隆,就是说从一个对象中复制出一个新对象出来,其状态和之前的完全一致,当然我们也可以通过构造方法或者set注入,但是这个效率不高,首先一个对象要重写clone方法,必须写实现Cloneable接口,重写clone方法,调用父类clone方法。

深克隆和浅克隆:

克隆有深克隆和浅克隆之分,主要区别在于对引用对象的处理。

浅拷贝:仅仅克隆基本类型变量,而不克隆引用类型的变量
深克隆:既克隆基本类型变量,也克隆引用类型变量

浅克隆

class My implements Cloneable {
    int my1;
    public My(int a) {
        this.my1 = a;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class MyObject implements Cloneable {

    public int a;
    public My my;

    public MyObject(int a, My my) {
        this.a = a;
        this.my = my;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        MyObject myObject1 = new MyObject(1,new My(1));
        MyObject myObject2=(MyObject)myObject1.clone();

        System.out.println(myObject1==(myObject2));       //false
        System.out.println(myObject1.a==myObject2.a);     //true
        System.out.println(myObject1.my==(myObject2.my)); //true

        System.out.println("-----------------------");

        System.out.println(myObject1.a+"---"+myObject2.a);             // 1---1
        System.out.println(myObject1.my.my1+"----"+myObject2.my.my1);  //1----1
        myObject1.my.my1=12;
        myObject1.a=12;
        System.out.println(myObject1.a+"---"+myObject2.a);             //12---1
        System.out.println(myObject1.my.my1+"----"+myObject2.my.my1);  //12----12
    }
}

上述,myObject2仅仅克隆的是myObject1 中 My 的地址引用,myObject1与myObject2的my属性指向的其实是同一个对象。所以就会引发出一个问题,myObject1.my内部的属性,myObject2.my也被修改了。要是myObject1.my=new My()..,修改其中一个则不会影响到副本,myObject1.my引用地址改变,指向对象不同了。

 

深克隆:

class My implements Cloneable {
    int my1;
    public My(int a) {
        this.my1 = a;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        My my = (My) super.clone();
        my.my1=this.my1;
        //my.Str=new String(this.Str);
        return my;

    }
}
public class MyObject implements Cloneable {

    public int a;
    public My my;

    public MyObject(int a, My my) {
        this.a = a;
        this.my = my;
    }
    @Override
    protected Object clone() throws CloneNotSupportedException {
        MyObject myObject=(MyObject) super.clone();
        myObject.a=this.a;
        myObject.my=(My)this.my.clone();
        return myObject;

    }

    public static void main(String[] args) throws CloneNotSupportedException {
        MyObject myObject1 = new MyObject(1,new My(1));
        MyObject myObject2=(MyObject)myObject1.clone();

        System.out.println(myObject1==(myObject2));           //false
        System.out.println(myObject1.a==myObject2.a);         //true
        System.out.println(myObject1.my==(myObject2.my));     //false

        System.out.println("-----------------------");

        System.out.println(myObject1.a+"---"+myObject2.a);             // 1---1
        System.out.println(myObject1.my.my1+"----"+myObject2.my.my1);  //1----1
        myObject1.my.my1=12;
        myObject1.a=12;
        System.out.println(myObject1.a+"---"+myObject2.a);             //12---1
        System.out.println(myObject1.my.my1+"----"+myObject2.my.my1);  //12----1

    }
}

引用不同,值一样,克隆成功。

要是修改成文中那样的深克隆,需要修改大量的类,对一个企业级项目来说,影响是巨大的。因此,我们也只能通过序列化的方式来实现对象的克隆,占用空间来节省时间!而且是非侵入的,不需要修改目标代码就可以实现!

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

返回类名+“@”+对象的16进制表示的哈希值,建议所有子类重写该方法。

 

7、protected void finalize() throws Throwable { }

简单说,finalize方法是对象回收器回收时将会触发的一个方法。

在java中存在垃圾回收器回收无用对象所占据的内存资源。存在有一些特殊情况,某些对象获得了一块特殊的内存空间(非使用new),垃圾回收器只会释放由new创建的内存,所以无法处理该内存,所以允许在类中定义一个finalize方法处理该内存。

其原理是一旦垃圾回收器准备去释放该区域,先调用该方法,方法处理一些重要工作,在下一次垃圾回收才会对象所占的内存。

例如在分配内存是采用了c中的malloc()函数,如果不在finalize中调用free()函数,内存将无法回收。

但是通常我们不应该将finalize方法当做通用的清理方法,因为垃圾回收可能不会发生,finalize方法得不到调用,因为垃圾回收本身也是需要消耗资源,如果不主动调用,在内存未满并不会发生。

finalize方法还可以用作某些终结条件的验证,例如当某个对象可以被回收时,假设是一个文件,对象被回收前应该关闭这个文件。只要对象存在未被清理的部分程序就存在缺陷,当某次finalize调用可以发现该问题所在。

 

8、wait,notify,notifyAll

wait方法是指是的当前线程阻塞,但是前提线程必须获取所对象,所有一般通synchronize关键字使用,在synchronize内可以保证线程必定获取到锁。当线程执行wait方法,便会释放所对象,当前线程重新进入等待状态,让出cpu,只有当被notify,notifyAll唤醒时,该线程重新进入就绪状态,一旦获取到cpu执行权,继续执行。

注意的是notify,notifyAll方法并不是立即释放锁,所得释放需要看代码块执行情况,

notify,notifyAll区别:

notify随机唤醒一个等待的线程,notifyAll唤醒所有等待的线程,哪一个线程获取到cpu便会有限执行。

wait(long timeout, int nanos),wait() ,wait(long timeout)

wait(long timeout, int nanos)和,wait(long timeout)如果线程在等待时间未被唤醒,将会自动醒来,int nanos指timeout的额外的时间。

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值