Java提高篇(一)——Object详解

大家都知道Object是所有类的父类,任何类都默认继承Object。
理论上Object类是所有类的父类,即直接或间接的继承java.lang.Object类。由于所有的类都继承在Object类,因此省略了extends Object关键字。

Object主要有以下方法

返回类型 方法名 说明
protected Object clone() 创建并返回此对象的一个副本。
boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。
protected void finalize() 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
Class getClass() 返回此 Object 的运行时类。
int hashCode() 返回该对象的哈希码值。
void notify() 唤醒在此对象监视器上等待的单个线程。
void notifyAll() 唤醒在此对象监视器上等待的所有线程。
String toString() 返回该对象的字符串表示。
void wait() 在其他线程调用此对象的notify()方法或notifyAll()方法前导致当前线程等待
void wait(long timeout) 在其他线程调用此对象的notify()方法或notifyAll()方法,或者超过指定的时间量前,导致当前线程等待
void wait(long timeout, int nanos) 在其他线程调用此对象的notify()方法或notifyAll()方法,或者其他某个线程中断当前线程,或者已超过某个实际时间量前,导致当前线程等待。

注意:
Object类中的getClass(),notify(),notifyAll(),wait()等方法被定义为final类型,因此不能重写。

一、clone()方法

保护方法,实现对象的浅复制,只有实现了Cloneable接口才可以调用该方法,否则抛出CloneNotSupportedException异常。
源码如下

  protected Object clone() throws CloneNotSupportedException {
        if (!(this instanceof Cloneable)) {
            throw new CloneNotSupportedException("Class " + getClass().getName() +
                                                 " doesn't implement Cloneable");
        }

        return internalClone();
    }

主要是JAVA里除了8种基本类型传参数是值传递,其他的类对象传参数都是引用传递,我们有时候不希望在方法里讲参数改变,这是就需要在类中复写clone方法(实现深复制)。

创建并返回此对象的一个副本。“副本”的准确含义可能依赖于对象的类。

clone与copy的区别

假设现在有一个People对象,People people = new People(“ZhangSan”,18)。

通常我们会有这样的赋值People people2 = people,这个时候只是简单了copy了一下reference,people2 和people2都指向内存中同一个object,这样people或者people2的一个操作都可能影响到对方。打个比方,如果我们通过people .raiseSalary()方法改变了salary域的值,那么people 2通过etSalary()方法得到的就是修改之后的salary域的值,显然这不是我们愿意看到的。

我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候我们就可以使用Clone来满足我们的需求。People people2=people .clone(),这时会生成一个新的People 对象,并且和people 具有相同的属性值和方法。

二、equals()方法

源码如下

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

Object中的equals方法是直接判断this和obj本身的值是否相等,即用来判断调用equals的对象和形参obj所引用的对象是否是同一对象。

所谓同一对象就是指内存中同一块存储单元,如果this和obj指向的hi同一块内存对象,则返回true,如果this和obj指向的不是同一块内存,则返回false。

注意:即便是内容完全相等的两块不同的内存对象,也返回false。
如果是同一块内存,则object中的equals方法返回true,如果是不同的内存,则返回false

大家都知道

  • 1、"abc".equals("acd")比较的是内容是否相等
  • 2、 "abc" == "acd"比较的是内存地址是否相等
    1中比较的是内容相等,而源码中的equal(Object obj)比较的明明是内存地址是否相等啊。什么状况???,我们这里看看String的源码
 public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String) anObject;
            int n = length();
            if (n == anotherString.length()) {
                int i = 0;
                while (n-- != 0) {
                    if (charAt(i) != anotherString.charAt(i))
                            return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

很明显,String类对equals(Object obj)方法进行了重写,比较的是内容。
注意很多类都已重写equals(Object obj)方法。

三finalize()方法

protected void finalize() throws Throwable { }

该方法用于释放资源。因为无法确定该方法什么时候被调用,很少使用。

Java允许在类中定义一个名为finalize()的方法。它的工作原理是:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用其finalize()方法。并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。

关于垃圾回收,有三点需要记住:
  - 1、对象可能不被垃圾回收。只要程序没有濒临存储空间用完的那一刻,对象占用的空间就总也得不到释放。
  - 2、垃圾回收并不等于“析构”。
  - 3、垃圾回收只与内存有关。使用垃圾回收的唯一原因是为了回收程序不再使用的内存。

finalize()的用途:
  无论对象是如何创建的,垃圾回收器都会负责释放对象占据的所有内存。这就将对finalize()的需求限制到一种特殊情况,即通过某种创建对象方式以外的方式为对象分配了存储空间。
  不过这种情况一般发生在使用“本地方法”的情况下,本地方法是一种在Java中调用非Java代码的方式。

四getClass()方法

 public final Class getClass() {
      return shadow$_klass_;
    }

返回次Object的运行时类类型。
不可重写,要调用的话,一般和getName()联合使用,如getClass().getName();

五、hashCode()方法

public int hashCode() {
        return identityHashCode(this);
    }

    // Android-changed: add a local helper for identityHashCode.
    // Package-private to be used by j.l.System. We do the implementation here
    // to avoid Object.hashCode doing a clinit check on j.l.System, and also
    // to avoid leaking shadow$_monitor_ outside of this class.
    /* package-private */ static int identityHashCode(Object obj) {
        int lockWord = obj.shadow$_monitor_;
        final int lockWordStateMask = 0xC0000000;  // Top 2 bits.
        final int lockWordStateHash = 0x80000000;  // Top 2 bits are value 2 (kStateHash).
        final int lockWordHashMask = 0x0FFFFFFF;  // Low 28 bits.
        if ((lockWord & lockWordStateMask) == lockWordStateHash) {
            return lockWord & lockWordHashMask;
        }
        return identityHashCodeNative(obj);
    }

    @FastNative
    private static native int identityHashCodeNative(Object obj);

返回该对象的哈希码值

该方法用于哈希查找,可以减少在查找中使用equals的次数,重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。

一般必须满足obj1.equals(obj2)==true。可以推出obj1.hash- Code()==obj2.hashCode(),但是hashCode相等不一定就满足equals。不过为了提高效率,应该尽量使上面两个条件接近等价。
如果不重写hashcode(),在HashSet中添加两个equals的对象,会将两个对象都加入进去。

六、toString()方法

Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。

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

该方法用得比较多,一般子类都有覆盖。
代码实例

public class TestOne {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Object obj = new Object();
        System.out.println(obj.toString());
    }

}

输出结果:java.lang.Object@15db9742

你可能感兴趣的:(Java提高篇(一)——Object详解)