zoukankan      html  css  js  c++  java
  • Java读源码之Object

    前言

    JDK版本: 1.8

    最近想看看jdk源码提高下技术深度(比较闲),万物皆对象,虽然Object大多native方法但还是很重要的。

    源码

    package java.lang;
    
    /**
     * Java中的始祖,万物皆Object
     * @since   JDK1.0
     */
    public class Object {
    
        private static native void registerNatives();
        static {
            // 保证在clinit()最先执行,从而调native方法
            registerNatives();
        }
    
        /**
         * 返回运行时的Class类文件,返回的是个泛型,运行时泛型会进行类型擦除,实际返回以自身为边界
         * 例如 new HelloWorld().getClass()
         * 返回 Class<? extends HelloWorld>
         */
        public final native Class<?> getClass();
    
        /**
         * 返回一个hash code整数,主要用于集合类使用,例如HashMap
         * 多次调用返回值必须一样,但是同一个应用执行了多份的时候,不保证多个执行中值相等
         * 如果两个对象调equels方法返回ture,那么hash code值一定相等(所以重写equels方法一定要重写hashCode方法)
         * 如果两个对象调equels方法返回false,hash code值不一定不相等,但是我们重写hashCode方法时,应该尽量做到不等,从而减少hash碰撞
         * 不同虚拟机的实现不太一样,但是主要是根据对象的内存地址来计算的
         */
        public native int hashCode();
    
        /**
         * 对于非空的对象进行逻辑上是否相等的比较,默认是比较的内存地址
         * 再次强调哈哈,如果两个对象调equels方法返回ture,那么hash code值一定相等(所以重写equels方法一定要重写hashCode方法)
         * 四大特性(1)reflexive自反性(2)symmetric对称性(3)transitive传递性(4)consistent一致性
         */
        public boolean equals(Object obj) {
            return (this == obj);
        }
    
        /**
         * 返回一个当前对象的副本,一般需要满足如下性质:
         * 		x.clone() != x
         *		x.clone().getClass() == x.getClass()
         *		x.clone().equals(x)
         * 可以根据需要实现浅拷贝和深拷贝,一般是浅拷贝
         * @throws  CloneNotSupportedException  Object没有实现Cloneable接口,本身是不能使用clone方法的,其子类调用clone方法会抛出此异常.只有实现了Cloneable才能正常使用
         * @see java.lang.Cloneable
         */
        protected native Object clone() throws CloneNotSupportedException;
    
        /**
         * 返回一个对象的字符串表示
         * 建议所有类都重写这个方法,因为不直观
         * 字符串内容,类名加上hash code转成16进制
         */
        public String toString() {
            return getClass().getName() + "@" + Integer.toHexString(hashCode());
        }
    
        /**
         * 用于随机唤醒一个在对象等待池中的线程
         * 被唤醒的线程不会立刻拿到对象的监视器锁,而是和其他在线程共同竞争,拿到锁之后恢复到调用wait方法时的同步状态
         * 同一时间只有一个线程能拿到监视器锁
         *
         * @throws  IllegalMonitorStateException  如果当前执行notify方法的线程没拿到对象的监视器锁
         */
        public final native void notify();
    
        /**
         * 一次唤醒所有等待池中的线程,其他和notify方法一样
         */
        public final native void notifyAll();
    
        /**
         * 持有对象监视器的线程可以执行awit方法把自己放入等待池中,并且放弃持有该对象的所有同步资源,不会放弃获取的其他对象的同步资源
         * 有四种情况线程可以逃出等待池:
         *		其他线程调用notify方法
         *		其他线程调用notifyAll方法
         *		其他线程调用interrupts方法
         *		超时时间到了
         * 逃出等待池拿到锁之后恢复到调用wait方法时的同步状态
         * 特别强调,如果因为interrupts逃出了等待池,不会立刻抛出InterruptedException,需要等到线程拿到锁
         * 由于偶尔会发生伪唤醒(没有调用notify或interrupts也没超时),所以我们在编码时应该如下例:
         *      synchronized (obj) {
         *    		while (<condition does not hold>)
         *        		obj.wait(timeout);
         *    			... // Perform action appropriate to condition
         *		}
         * @param      timeout   在等待池中的最长等待时间,时间到了就出狱了,如果值为0,则无期徒刑等待保释
         * @throws  IllegalArgumentException     超时时间是负数
         * @throws  IllegalMonitorStateException  当前线程没有拿到监视器锁
         * @throws  InterruptedException 中断位为true
         */
        public final native void wait(long timeout) throws InterruptedException;
    
        /**
         * 提供纳秒级别的等待控制,其他同wait(long timeout)
         * @param      nanos     额外的纳秒时间
         *                       0-999999.
         * @throws  IllegalArgumentException     timeout是负数,nanos是负数或者大于999999.
         */
        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(long timeout)方法一样,只是没有超时时间
         */
        public final void wait() throws InterruptedException {
            wait(0);
        }
    
        /**
         * 当垃圾收集器判断此对象没有被任何引用,是垃圾对象了,由垃圾收集器执行此方法销毁对象,所以何时执行是不确定的
         * JVM保证垃圾收集器调用此方法时候,该对象的锁不被任何线程持有了
         * finalize方法只会被执行一次,所以我们可以重写此方法特定一些清除工作,或者给对象一次复活机会,但是不建议重写此方法
         * @throws Throwable the {@code Exception} raised by this method
         * @see java.lang.ref.WeakReference
         * @see java.lang.ref.PhantomReference
         */
        protected void finalize() throws Throwable { }
    }
    
    

    实践

    clone()

    public class ObjectCloneTest {
    
    
        /**
         * 不实现 Cloneable 接口
         *
         * 输出:
         * Exception in thread "main" java.lang.CloneNotSupportedException: study.ObjectCloneTest$Obj
         * 	at java.lang.Object.clone(Native Method)
         * 	at study.ObjectCloneTest$Obj.main(ObjectCloneTest.java:24)
         */
        private static class Obj {
            public static void main(String[] args) throws CloneNotSupportedException {
                Obj o1 = new Obj();
                Object o2 = o1.clone();
            }
        }
    
        /**
         * 实现 Cloneable 接口,从结果看出默认实现是浅拷贝
         *
         * 输出:
         * 两个对象地址相同么
         * false
         * 两个对象的属性地址相同么
         * true
         * 改变其中一个属性会变么?
         * [1, 2]
         * [1, 2]
         */
        private static class ObjShallowCopy implements Cloneable {
    
            private List<String> list = new ArrayList<>();
    
            @Override
            protected Object clone() throws CloneNotSupportedException {
                return super.clone();
            }
    
            public static void main(String[] args) throws CloneNotSupportedException {
                ObjShallowCopy o1 = new ObjShallowCopy();
                o1.list.add("1");
                ObjShallowCopy o2 = (ObjShallowCopy) o1.clone();
                System.out.println("两个对象地址相同么");
                System.out.println(o1 == o2);
                System.out.println("两个对象的属性地址相同么");
                System.out.println(o1.list == o2.list);
                System.out.println("改变其中一个属性会变么?");
                o2.list.add("2");
                System.out.println(o1.list.toString());
                System.out.println(o2.list.toString());
    
            }
    
        }
    
        /**
         * 实现 Cloneable 接口,比较笨拙的做了一层深拷贝,只为了演示,深拷贝也可以通过序列号等方式实现
         *
         * 输出:
         * 两个对象地址相同么
         * false
         * 两个对象的属性地址相同么
         * false
         * 改变其中一个属性会变么?
         * [1]
         * [1, 2]
         */
        private static class ObjDeepCopy implements Cloneable {
    
            private List<String> list = new ArrayList<>();
    
            @Override
            protected Object clone() throws CloneNotSupportedException {
                ObjDeepCopy obj = (ObjDeepCopy) super.clone();
                List<String> list = new ArrayList<>(obj.list.size());
                list.addAll(obj.list);
                obj.list = list;
                return obj;
            }
    
            public static void main(String[] args) throws CloneNotSupportedException {
                ObjDeepCopy o1 = new ObjDeepCopy();
                o1.list.add("1");
                ObjDeepCopy o2 = (ObjDeepCopy) o1.clone();
                System.out.println("两个对象地址相同么");
                System.out.println(o1 == o2);
                System.out.println("两个对象的属性地址相同么");
                System.out.println(o1.list == o2.list);
                System.out.println("改变其中一个属性会变么?");
                o2.list.add("2");
                System.out.println(o1.list.toString());
                System.out.println(o2.list.toString());
    
            }
    
        }
    }
    

    wait() 和 notify()

    public class ObjectWaitNotifyTest {
    
        private volatile boolean flag = true;
    
        public static void main(String[] args) {
            ObjectWaitNotifyTest obj = new ObjectWaitNotifyTest();
    
            new Thread(() -> {
                synchronized (obj) {
                    System.out.println("绝食!");
                    while (obj.flag == true) {
                        try {
                            obj.wait();
                            System.out.println("真香!");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } 
                    }
                }
            }).start();
    
            new Thread(() -> {
                synchronized (obj) {
                    obj.flag = false;
                    obj.notify();
                    System.out.println("海底捞走起!");
                }
            }).start();
    
            /**
             * 输出:
             * 绝食!
             * 海底捞走起!
             * 真香!
             */
        }
    }
    
  • 相关阅读:
    二分图 洛谷P2055 [ZJOI2009]假期的宿舍
    并查集 洛谷P1640 [SCOI2010]连续攻击游戏
    贪心 洛谷P2870 Best Cow Line, Gold
    贪心 NOIP2013 积木大赛
    快速幂 NOIP2013 转圈游戏
    倍增LCA NOIP2013 货车运输
    树形DP 洛谷P2014 选课
    KMP UVA1328 Period
    动态规划入门 BZOJ 1270 雷涛的小猫
    KMP POJ 2752Seek the Name, Seek the Fame
  • 原文地址:https://www.cnblogs.com/freshchen/p/11662421.html
Copyright © 2011-2022 走看看