Java一切皆对象之Object

阅读jdk源码是一条”漫漫长路“,当你坚持下来,对于码农来说是一个很大的提升,能在其中学到很多不一样的东西,希望大家坚持,话不多说,来看看Java超类Object。
Class Object是类Object结构的根。 每个班都有Object作为超类。 所有对象(包括数组)都实现了这个类的方法。

方法列表

public final native Class<?> getClass()
public native int hashCode()
public boolean equals(Object obj)
protected native Object clone() throws CloneNotSupportedException
public String toString()
public final native void notify()
public final native void notifyAll()
public final native void wait(long timeout) throws InterruptedException
public final void wait(long timeout, int nanos) throws InterruptedException
public final void wait() throws InterruptedException
protected void finalize() throws Throwable { }

方法说明

getClass方法

返回此Object的运行时类。 返回的类对象是被表示类的static synchronized方法锁定的对象。
实际结果的类型是Class<? extends |X|>其中|X|是静态类型上其表达的擦除getClass被调用。 例如,在此代码片段中不需要转换: 
Number n = 0; 
Class<? extends Number> c = n.getClass(); 

hashCode方法

该方法返回对象的哈希码,主要使用在哈希表中,比如JDK中的HashMap。

哈希码的通用约定如下:
 *在java程序执行过程中,在一个对象没有被改变的前提下,无论这个对象被调用多少次,hashCode方法都会返回相同的整数值。对象的哈希码没有必要在不同的程序中保持相同的值。
 *如果2个对象使用equals方法进行比较并且相同的话,那么这2个对象的hashCode方法的值也必须相等。
 *如果根据equals方法,得到两个对象不相等,那么这2个对象的hashCode值不需要必须不相同。但是,不相等的对象的hashCode值不同的话可以提高哈希表的性能。

equals方法

比较两个对象是否相等。Object类的默认实现,即比较2个对象的内存地址是否相等。
equals方法在非空对象引用上实现等价关系: 
 *自反性 :对于任何非空的参考值x , x.equals(x)应该返回true 。 
 *对称性 :对于任何非空引用值x和y , x.equals(y)应该返回true当且仅当y.equals(x)回报true 。 
 *传递性 :对于任何非空引用值x , y和z ,如果x.equals(y)回报true个y.equals(z)回报true ,然后x.equals(z)应该返回true 。 
 *一致性 :对于任何非空引用值x和y ,多次调用x.equals(y)始终返回true或始终返回false ,没有设置中使用的信息equals比较上的对象被修改。 

clone方法

创建并返回此对象的副本。 “复制”的精确含义可能取决于对象的类。 一般的意图是,对于任何对象x ,表达式: 
  x.clone() != x将是真实的,而且表达: 
  x.clone().getClass() == x.getClass()将是true ,但这些都不是绝对的要求。 通常情况是: 
  x.clone().equals(x)将是true ,这不是一个绝对的要求。 
按照惯例,返回的对象应该通过调用super.clone获得。如果一个类和它的所有超类(除了Object )遵守这个惯例,那将是x.clone().getClass() == x.getClass()的情况。 
按照惯例,此方法返回的对象应该与此对象(正被克隆)无关。 为了实现这一独立性,可能需要修改super.clone返回的对象的一个或多个字段。 通常,这意味着复制构成被克隆的对象的内部“深层结构”的任何可变对象,并通过引用该副本替换对这些对象的引用。 如果一个类仅包含原始字段或对不可变对象的引用,则通常情况下, super.clone返回的对象中的字段通常不需要修改。 
clone的方法Object执行特定的克隆操作。 首先,如果此对象的类不实现接口Cloneable ,则抛出CloneNotSupportedException 。 请注意,所有数组都被认为是实现接口Cloneable ,并且数组类型T[]的clone方法的返回类型是T[] ,其中T是任何引用或原始类型。 否则,该方法将创建该对象的类的新实例,并将其所有字段初始化为完全符合该对象的相应字段的内容,就像通过赋值一样。 这些字段的内容本身不被克隆。 因此,该方法执行该对象的“浅拷贝”,而不是“深度拷贝”操作。 
Object类本身并不实现接口Cloneable ,因此在类别为Object的对象上调用clone方法将导致运行时抛出异常。 

toString方法

Object对象的默认实现,即输出类的名字@实例的哈希码的16进制:getClass().getName() + '@' + Integer.toHexString(hashCode())。 建议所有子类覆盖此方法,容易让人阅读。 

notify方法

唤醒一个在此对象锁上等待的线程。如果所有的线程都在此对象上等待,那么只会选择一个线程。选择是任意性的,并在对实现做出决定时发生。一个线程在对象锁上等待可以调用wait方法。
直到当前线程放弃对象上的锁之后,被唤醒的线程才可以继续处理。被唤醒的线程将以常规方式与在该对象上主动同步的其他所有线程进行竞争。例如,唤醒的线程在作为锁定此对象的下一个线程方面没有可靠的特权或劣势。

notify方法只能被作为此对象锁的所有者的线程来调用。一个线程要锁的所有者,可以使用以下3种方法:
* 执行对象的同步实例方法
* 使用synchronized内置锁
* 对于Class类型的对象,执行同步静态方法
一次只能有一个线程拥有对象锁。
如果当前线程不是此对象锁的所有者的话会抛出IllegalMonitorStateException异常。

注意点:
因为notify只能在拥有对象锁的所有者线程中调用,否则会抛出IllegalMonitorStateException异常。

notifyAll方法

跟notify一样,唯一的区别就是会唤醒在此对象锁上等待的所有线程,而不是一个线程。

wait(long timeout) throws InterruptedException方法

wait方法会让当前线程等待直到另外一个线程调用对象的notify或notifyAll方法,或者超过参数设置的timeout超时时间。
跟notify和notifyAll方法一样,当前线程必须是此对象锁所有者,否则还是会发IllegalMonitorStateException异常。
wait方法会让当前线程(我们先叫做线程T)将其自身放置在对象的等待集中,并且会放弃对象锁。出于线程调度目的,线程T是不可用并处于休眠状态,直到发生以下四件事中的任意一件:
*其他某个线程调用此对象的notify方法,并且线程T碰巧被任选为被唤醒的线程
*其他某个线程调用此对象的notifyAll方法
*其他某个线程调用Thread.interrupt方法中断线程T
*时间到了参数设置的超时时间。如果timeout参数为0,则不会超时,会一直进行等待
在没有被通知、中断或超时的情况下,线程还可以唤醒一个所谓的虚假唤醒 (spurious wakeup)。虽然这种情况在实践中很少发生,但是应用程序必须通过以下方式防止其发生,即对应该导致该线程被提醒的条件进行测试,如果不满足该条件,则继续等待。换句话说,等待应总是发生在循环中,如下面的示例:
synchronized (obj) {
  while (<condition does not hold>)
    obj.wait(timeout);
    ... // Perform action appropriate to condition
  }

wait(long timeout, int nanos) throws InterruptedException方法

跟wait(long timeout)方法类似,多了一个nanos参数,这个参数表示额外时间(以毫微秒为单位,范围是 0-999999)。 所以超时的时间还需要加上nanos毫秒。
需要注意的是 wait(0, 0)和wait(0)效果是一样的,即一直等待。

wait() throws InterruptedException方法

跟之前的2个wait方法一样,只不过该方法一直等待,没有超时时间这个概念。

finalize方法

当垃圾收集确定不再有对该对象的引用时,垃圾收集器在对象上调用该对象。 一个子类覆盖了处理系统资源或执行其他清理的finalize方法。

大家可能会觉得本文终于看完了,不容易,但是我想说的是还得补习一下Object的工具类Objects一起讲,它和Object一起讲,原因是它们有密不可分的联系。

Objects类

该类由static用于对对象进行static实用方法组成。 这些实用程序包括用于计算对象的哈希码的null -safe或null方法,为对象返回一个字符串,并比较两个对象,其中我只挑几个典型的方法说一下。

方法列表

  1. public static boolean equals(Object a, Object b) {}
  2. public static boolean deepEquals(Object a, Object b) {}
  3. public static int hashCode(Object o) {}
  4. public static int hash(Object... values) {}
  5. public static String toString(Object o) {}
  6. public static String toString(Object o, String nullDefault) {}
  7. public static <T> int compare(T a, T b, Comparator<? super T> c) { }
  8. public static <T> T requireNonNull(T obj) {}
  9. public static <T> T requireNonNull(T obj, String message) {}
  10.public static boolean isNull(Object obj) {}
  11. public static boolean nonNull(Object obj) {}
  12. public static <T> T requireNonNull(T obj, Supplier<String> messageSupplier) {} 

equals方法

(a == b) || (a != null && a.equals(b));

源码很简单,但用相当的的方便,不用判断空减少代码量比如:

a != null && a.equals(b) //相当与Objects.equals(a,b)

deepEquals方法

        if (a == b)
            return true;
        else if (a == null || b == null)
            return false;
        else
            return Arrays.deepEquals0(a, b);

既可以用于对象的比较,也可以用于数组的比较,数组的比较大家可以看看Arrays.deepEquals0(a, b),采用递归深度比较数组,其实也很简单。

static boolean deepEquals0(Object e1, Object e2) {
        assert e1 != null;
        boolean eq;
        if (e1 instanceof Object[] && e2 instanceof Object[])
            eq = deepEquals ((Object[]) e1, (Object[]) e2);
        else if (e1 instanceof byte[] && e2 instanceof byte[])
            eq = equals((byte[]) e1, (byte[]) e2);
        else if (e1 instanceof short[] && e2 instanceof short[])
            eq = equals((short[]) e1, (short[]) e2);
        else if (e1 instanceof int[] && e2 instanceof int[])
            eq = equals((int[]) e1, (int[]) e2);
        else if (e1 instanceof long[] && e2 instanceof long[])
            eq = equals((long[]) e1, (long[]) e2);
        else if (e1 instanceof char[] && e2 instanceof char[])
            eq = equals((char[]) e1, (char[]) e2);
        else if (e1 instanceof float[] && e2 instanceof float[])
            eq = equals((float[]) e1, (float[]) e2);
        else if (e1 instanceof double[] && e2 instanceof double[])
            eq = equals((double[]) e1, (double[]) e2);
        else if (e1 instanceof boolean[] && e2 instanceof boolean[])
            eq = equals((boolean[]) e1, (boolean[]) e2);
        else
            eq = e1.equals(e2);
        return eq;
    }

deepEquals ((Object[]) e1, (Object[]) e2)源码如下:

public static boolean deepEquals(Object[] a1, Object[] a2) {
        if (a1 == a2)
            return true;
        if (a1 == null || a2==null)
            return false;
        int length = a1.length;
        if (a2.length != length)
            return false;

        for (int i = 0; i < length; i++) {
            Object e1 = a1[i];
            Object e2 = a2[i];

            if (e1 == e2)
                continue;
            if (e1 == null)
                return false;

            // 递归实现
            boolean eq = deepEquals0(e1, e2);

            if (!eq)
                return false;
        }
        return true;
    }

hashCode方法

return o != null ? o.hashCode() : 0;

同样,可以方便大家应用,这不做多说明了。

hash方法

return Arrays.hashCode(values);

Arrays.hashCode(values)源码

public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

数组的hashCode公式:((31 + s0)31 + s1) 31 + s2 + …最后等31^n + s031^(n-1) + s131(n-2)+…,说明s0代表数组第一个元素的hashCode值,sn代表数组第n个元素的hashCode值。

##toString(Object o)方法

return String.valueOf(o);

避免空指针异常,String.valueOf(o)源码

return (obj == null) ? "null" : obj.toString();

其实我说这个类的目的想让大家知道这个类,熟悉这个类,并用上这个类。沉下心来,来阅读jdk之类,兄弟们。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值