zoukankan      html  css  js  c++  java
  • Object类

    概览

     
     
     
    11
     
     
     
     
    1
    public native int hashCode()
    2
    public boolean equals(Object obj)
    3
    protected native Object clone() throws CloneNotSupportedException
    4
    public String toString()
    5
    public final native Class<?> getClass()
    6
    protected void finalize() throws Throwable {}
    7
    public final native void notify()
    8
    public final native void notifyAll()
    9
    public final native void wait(long timeout) throws InterruptedException
    10
    public final void wait(long timeout, int nanos) throws InterruptedException
    11
    public final void wait() throws InterruptedException
    2
    public boolean equals(Object obj)
     
     

    equals()

    1. 等价关系

    Ⅰ 自反性

     
     
     
    1
     
     
     
     
    1
    x.equals(x); // true
     
     

    Ⅱ 对称性

     
     
     
    1
     
     
     
     
    1
    x.equals(y) == y.equals(x); // true
     
     

    Ⅲ 传递性

     
     
     
    2
     
     
     
     
    1
    if (x.equals(y) && y.equals(z))
    2
        x.equals(z); // true;
     
     

    Ⅳ 一致性

    多次调用 equals() 方法结果不变

     
     
     
    1
     
     
     
     
    1
    x.equals(y) == x.equals(y); // true
     
     

    Ⅴ 与 null 的比较

    对任何不是 null 的对象 x 调用 x.equals(null) 结果都为 false

     
     
     
    1
     
     
     
     
    1
    x.equals(null); // false;
     
     

    2. 等价与相等

    • 对于基本类型,== 判断两个值是否相等,基本类型没有 equals() 方法。
    • 对于引用类型,== 判断两个变量是否引用同一个对象,而 equals() 判断引用的对象是否等价。
     
     
     
    4
     
     
     
     
    1
    Integer x = new Integer(1);
    2
    Integer y = new Integer(1);
    3
    System.out.println(x.equals(y)); // true
    4
    System.out.println(x == y);      // false
     
     

    3. 实现

    • 检查是否为同一个对象的引用,如果是直接返回 true;
    • 检查是否是同一个类型,如果不是,直接返回 false;
    • 将 Object 对象进行转型;
    • 判断每个关键域是否相等。

    hashCode()

    hashCode() 返回散列值,而 equals() 是用来判断两个对象是否等价。等价的两个对象散列值一定相同,但是散列值相同的两个对象不一定等价。

    为了保证散列值相同的两个对象一定相等,所以在覆盖 equals() 方法时应当总是覆盖 hashCode() 方法,保证等价的两个对象散列值也相等。

    下面的代码中,新建了两个等价的对象,并将它们添加到 HashSet 中。我们希望将这两个对象当成一样的,只在集合中添加一个对象,但是因为 EqualExample 没有实现 hasCode() 方法,因此这两个对象的散列值是不同的,最终导致集合添加了两个等价的对象。

     
     
     
    7
     
     
     
     
    1
    EqualExample e1 = new EqualExample(1, 1, 1);
    2
    EqualExample e2 = new EqualExample(1, 1, 1);
    3
    System.out.println(e1.equals(e2)); // true
    4
    HashSet<EqualExample> set = new HashSet<>();
    5
    set.add(e1);
    6
    set.add(e2);
    7
    System.out.println(set.size());   // 2
     
     

    理想的散列函数应当具有均匀性,即不相等的对象应当均匀分布到所有可能的散列值上。这就要求了散列函数要把所有域的值都考虑进来。可以将每个域都当成 R 进制的某一位,然后组成一个 R 进制的整数。R 一般取 31,因为它是一个奇素数,如果是偶数的话,当出现乘法溢出,信息就会丢失,因为与 2 相乘相当于向左移一位。

    一个数与 31 相乘可以转换成移位和减法:31*x == (x<<5)-x,编译器会自动进行这个优化。

     
     
     
    8
     
     
     
     
    1
    @Override
    2
    public int hashCode() {
    3
        int result = 17;
    4
        result = 31 * result + x;
    5
        result = 31 * result + y;
    6
        result = 31 * result + z;
    7
        return result;
    8
    }
     
     

    toString()

    默认返回 ToStringExample@4554617c 这种形式,其中 @ 后面的数值为散列码的无符号十六进制表示。

     
     
     
    xxxxxxxxxx
     
     
     
     
    1
    public class ToStringExample {
    2
        private int number;
    3
    4
        public ToStringExample(int number) {
    5
            this.number = number;
    6
        }
    7
    }
     
     
     
     
     
    2
     
     
     
     
    1
    ToStringExample example = new ToStringExample(123);
    2
    System.out.println(example.toString());
     
     
     
     
     
    1
     
     
     
     
    1
    ToStringExample@4554617c
     
     

    clone()

    cloneable

    clone() 是 Object 的 protected 方法,它不是 public,一个类不显式去重写 clone(),其它类就不能直接去调用该类实例的 clone() 方法。

     
     
     
    4
     
     
     
     
    1
    public class CloneExample {
    2
        private int a;
    3
        private int b;
    4
    }
     
     
     
     
     
    3
     
     
     
     
    1
    CloneExample e1 = new CloneExample();
    2
    // CloneExample e2 = e1.clone(); // 'clone()' has protected access in 'java.lang.Object'
    3
    3
     
     

    重写 clone() 得到以下实现:

     
     
     
    9
     
     
     
     
    1
    public class CloneExample {
    2
        private int a;
    3
        private int b;
    4
    5
        @Override
    6
        public CloneExample clone() throws CloneNotSupportedException {
    7
            return (CloneExample)super.clone();
    8
        }
    9
    }
    8
        }
     
     
     
     
     
    6
     
     
     
     
    1
    CloneExample e1 = new CloneExample();
    2
    try {
    3
        CloneExample e2 = e1.clone();
    4
    } catch (CloneNotSupportedException e) {
    5
        e.printStackTrace();
    6
    }
     
     
     
     
     
    1
     
     
     
     
    1
    java.lang.CloneNotSupportedException: CloneExample
     
     

    以上抛出了 CloneNotSupportedException,这是因为 CloneExample 没有实现 Cloneable 接口。

    应该注意的是,clone() 方法并不是 Cloneable 接口的方法,而是 Object 的一个 protected 方法。Cloneable 接口只是规定,如果一个类没有实现 Cloneable 接口又调用了 clone() 方法,就会抛出 CloneNotSupportedException。

     
     
     
    9
     
     
     
     
    1
    public class CloneExample implements Cloneable {
    2
        private int a;
    3
        private int b;
    4
    5
        @Override
    6
        public Object clone() throws CloneNotSupportedException {
    7
            return super.clone();
    8
        }
    9
    }
     
     

    浅拷贝

    拷贝对象和原始对象的引用类型引用同一个对象。

     
     
     
    24
     
     
     
     
    1
    public class ShallowCloneExample implements Cloneable {
    2
    3
        private int[] arr;
    4
    5
        public ShallowCloneExample() {
    6
            arr = new int[10];
    7
            for (int i = 0; i < arr.length; i++) {
    8
                arr[i] = i;
    9
            }
    10
        }
    11
    12
        public void set(int index, int value) {
    13
            arr[index] = value;
    14
        }
    15
    16
        public int get(int index) {
    17
            return arr[index];
    18
        }
    19
    20
        @Override
    21
        protected ShallowCloneExample clone() throws CloneNotSupportedException {
    22
            return (ShallowCloneExample) super.clone();
    23
        }
    24
    }
    13
            arr[index] = value;
     
     
     
     
     
    9
     
     
     
     
    1
    ShallowCloneExample e1 = new ShallowCloneExample();
    2
    ShallowCloneExample e2 = null;
    3
    try {
    4
        e2 = e1.clone();
    5
    } catch (CloneNotSupportedException e) {
    6
        e.printStackTrace();
    7
    }
    8
    e1.set(2, 222);
    9
    System.out.println(e2.get(2)); // 222
     
     

    深拷贝

    拷贝对象和原始对象的引用类型引用不同对象。

     
     
     
    29
     
     
     
     
    1
    public class DeepCloneExample implements Cloneable {
    2
    3
        private int[] arr;
    4
    5
        public DeepCloneExample() {
    6
            arr = new int[10];
    7
            for (int i = 0; i < arr.length; i++) {
    8
                arr[i] = i;
    9
            }
    10
        }
    11
    12
        public void set(int index, int value) {
    13
            arr[index] = value;
    14
        }
    15
    16
        public int get(int index) {
    17
            return arr[index];
    18
        }
    19
    20
        @Override
    21
        protected DeepCloneExample clone() throws CloneNotSupportedException {
    22
            DeepCloneExample result = (DeepCloneExample) super.clone();
    23
            result.arr = new int[arr.length];
    24
            for (int i = 0; i < arr.length; i++) {
    25
                result.arr[i] = arr[i];
    26
            }
    27
            return result;
    28
        }
    29
    }
     
     
     
     
     
    9
     
     
     
     
    1
    DeepCloneExample e1 = new DeepCloneExample();
    2
    DeepCloneExample e2 = null;
    3
    try {
    4
        e2 = e1.clone();
    5
    } catch (CloneNotSupportedException e) {
    6
        e.printStackTrace();
    7
    }
    8
    e1.set(2, 222);
    9
    System.out.println(e2.get(2)); // 2
     
     

    clone() 的替代方案

    使用 clone() 方法来拷贝一个对象即复杂又有风险,它会抛出异常,并且还需要类型转换。Effective Java 书上讲到,最好不要去使用 clone(),可以使用拷贝构造函数或者拷贝工厂来拷贝一个对象。

     
     
     
    x
     
     
     
     
    1
    public class CloneConstructorExample {
    2
    3
        private int[] arr;
    4
    5
        public CloneConstructorExample() {
    6
            arr = new int[10];
    7
            for (int i = 0; i < arr.length; i++) arr[i] = i;
    8
        }
    9
    10
        public CloneConstructorExample(CloneConstructorExample original) {
    11
            arr = new int[original.arr.length];
    12
            for (int i = 0; i < original.arr.length; i++) {
    13
                arr[i] = original.arr[i];
    14
            }
    15
        }
    16
    17
        public void set(int index, int value) {
    18
            arr[index] = value;
    19
        }
    20
    21
        public int get(int index) {
    22
            return arr[index];
    23
        }
    24
    }
    13
            arr = new int[original.arr.length];
     
     
     
     
     
    4
     
     
     
     
    1
    CloneConstructorExample e1 = new CloneConstructorExample();
    2
    CloneConstructorExample e2 = new CloneConstructorExample(e1);
    3
    e1.set(2, 222);
    4
    System.out.println(e2.get(2)); // 2
    2
    CloneConstructorExample e2 = new CloneConstructorExample(e1);
     
     

    getClass()

    getClass()方法是一个获取当前的对象的类型的类的对象。

     
     
     
    15
     
     
     
     
    1
    package com.xzj.Test;
    2
    3
    /*  @ author thisxzj
    4
     *   @ create 2019-02-26 14:59
    5
     */
    6
    public class Base {
    7
        public static void main(String[] args) {
    8
            Person person = new Person();
    9
            System.out.println(person.getClass().toString());
    10
            System.out.println(person.getClass().getDeclaredFields()[0].toGenericString());
    11
        }
    12
    }
    13
    class Person {...}
    14
    15
    }
     
     

    运行结果:

     
     
     
    2
     
     
     
     
    1
    class com.xzj.Test.Person
    2
    int com.xzj.Test.Person.age
     
     

    每一个Class类型的的对象中都保留着一个类的的完整的信息。其中包括域、方法等信息。

    例如上面的第二个println信息。

    finalize()

    finalize()是Object类中的方法。当垃圾回收器将要回收对象所占内存之前被调用,即当一个对象被虚拟机宣告死亡时会先调用它finalize()方法,让此对象处理在它被回收之前的最后工作。

    当以恶搞对象在被判定应当被回收的时候,仍然有机会不被回收。但是又下面的两个条,对象覆写了finalize()方法:在finalize()方法中重新引用到"GC Roots”链上。 finalize()只会在对象内存回收前被调用一次。

    finalize()的调用具有不确定行,只保证方法会调用,但不保证方法里的语句任务会被执行完。

    wait(),notify()

    wait和notify它们是Object的方法。这一组信号一般和synchronized关键字组合使用。前面在synchronized部分有过详细的举例。

    调用wait方法时,线程进入等待状态,并且会释放synchronized的锁。

    一个线程使用了wait的方法之后,重新苏醒条件是:其他的线程对这个锁使用了notify方法,并且这个锁没有被占用。

    得到了notify信号之后,线程从执行wait的地方恢复执行。

    添加参数的wait和notify就是表示有时间的延迟的wait和notify。

    wait() 和 sleep() 的区别 sleep是Thread的静态方法

    wait() 是 Object 的方法,而 sleep() 是 Thread 的静态方法。

    wait() 会释放锁,sleep() 不会。

  • 相关阅读:
    迟滞电压比较器
    单调谐小信号放大器
    汇编指令
    渗透测试之信息收集
    DVWA——文件包含
    DVWA——文件上传
    文件上传漏洞与利用
    在Metasploit中使用PostgreSQL
    软件安装方法
    XML外部实体(XXE)
  • 原文地址:https://www.cnblogs.com/zjxu97/p/10438073.html
Copyright © 2011-2022 走看看