Object源码详解

一、结构如下

发

二、方法介绍

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

类首次加载时执行,虚拟机调用initializeSystemClass方法,即静态初始化程序,来初始化静态变量、调用静态方法等。native代表java程序调用非java代码的接口。registerNatives()这个方法将编译好的动态库加载到jvm中,简单来说就是给这些native本地方法提供实现。

public final native Class<?> getClass();

返回对象的运行时类对象,通常使用在反射中。

public native int hashCode();

hashCode文档注释中仅仅规定了JVM厂商实现hashCode方法的一些规范(一致性,equals相等hashCode也相等,equals不相等hashCode不是一定不相等),类 Object 定义的 hashCode 方法为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 Java™ 编程语言不需要这种实现技术。)到这里你是不是很好奇他具体的算法是什么样的呢?我们就来看看OpenJDK8的源码C++中是如何实现的。

// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stwRandom}
// * CRC32 of {obj,stwRandom} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
//   2654435761 = 2^32 * Phi (golden ratio)
//   HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stwRandom ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stwRandom) is appealing, but can result
//   in undesirable regularity in the hashCode values of adjacent objects
//   (objects allocated back-to-back, in particular).  This could potentially
//   result in hashtable collisions and reduced hashtable efficiency.
//   There are simple ways to "diffuse" the middle address bits over the
//   generated hashCode values:
//

static inline intptr_t get_next_hash(Thread * Self, oop obj) {
  intptr_t value = 0 ;
  if (hashCode == 0) {
     // This form uses an unguarded global Park-Miller RNG,
     // so it's possible for two threads to race and generate the same RNG.
     // On MP system we'll have lots of RW access to a global, so the
     // mechanism induces lots of coherency traffic.
     value = os::random() ;
  } else
  if (hashCode == 1) {
     // This variation has the property of being stable (idempotent)
     // between STW operations.  This can be useful in some of the 1-0
     // synchronization schemes.
     intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
     value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
  } else
  if (hashCode == 2) {
     value = 1 ;            // for sensitivity testing
  } else
  if (hashCode == 3) {
     value = ++GVars.hcSequence ;
  } else
  if (hashCode == 4) {
     value = cast_from_oop<intptr_t>(obj) ;
  } else {
     // Marsaglia's xor-shift scheme with thread-specific state
     // This is probably the best overall implementation -- we'll
     // likely make this the default in future releases.
     unsigned t = Self->_hashStateX ;
     t ^= (t << 11) ;
     Self->_hashStateX = Self->_hashStateY ;
     Self->_hashStateY = Self->_hashStateZ ;
     Self->_hashStateZ = Self->_hashStateW ;
     unsigned v = Self->_hashStateW ;
     v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
     Self->_hashStateW = v ;
     value = v ;
  }

  value &= markOopDesc::hash_mask;
  if (value == 0) value = 0xBAD ;
  assert (value != markOopDesc::no_hash, "invariant") ;
  TEVENT (hashCode: GENERATE) ;
  return value;
}

可见,一共有5种实现方式,返回随机数、对对象地址做一些逻辑位运算、返回1、直接使用地址、根据线程状态返回不同的结果。

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

重写equals的规则:

  1. 自反性
  2. 对称性
  3. 传递性
  4. 一致性
  5. x.equals(null) = false
  6. 两个对象是不同类,返回false
  7. 重写equals要判断hashCode方法需不需要重写,因为我们要满足equals返回true的两个对象hashCode方法返回值也是true。

这里Object父类中使用地址来比较两个对象是否相等。

protected native Object clone() throws CloneNotSupportedException;

调用clone()方法要实现Cloneable接口。

重写克隆满足的条件:

  1. x.clone() != x
  2. x.clone().getClass() = x.getClass()
  3. x.clone().equals(x) = true

深拷贝:拷贝和被拷贝两个对象的内存空间除了不可变对象没有任何交集(我的理解)。
浅拷贝:拷贝和被拷贝两个对象存在某一属性或属性的属性指向同一个可变对象。

深拷贝实现
拷贝对象要实现cloneable接口
所有对象的可变属性都要实现cloneable接口,其中,属性的可变属性也要实现cloneable接口

举例代码如下

static class Head implements Cloneable{
	public  Face face;
	
	public Head() {}
	public Head(Face face){this.face = face;}
	@Override
	protected Object clone() throws CloneNotSupportedException {
		//return super.clone();
		Head newHead = (Head) super.clone();
		newHead.face = (Face) this.face.clone();
		return newHead;
	}
} 

static class Face implements Cloneable{
	@Override
	protected Object clone() throws CloneNotSupportedException {
		return super.clone();
	}
}
public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

全类名+@+对象哈希码的无符号十六进制表示

public final native void wait(long timeout) throws InterruptedException;

1. 作用:此方法使当前线程(称为 T)将自己置于此对象的等待集中,然后放弃对该对象的任何和所有同步声明。线程 T 出于线程调度目的而被禁用并处于休眠状态,直到发生以下四种情况之一:另一个线程为此对象调用 notify() 方法或 notifyAll() 方法而恰好被选中,或者指定的时间已过,或者其他线程调用该线程interrupt方法。interrupt会打断阻塞状态,并抛出一个InterruptedException异常一般我们会捕获这个异常然后做后续的处理。
2. 条件:当前线程必须拥有此对象的监视器。
3. 苏醒:线程notify后,从该对象的等待集中移除,并重新启用线程调度,也就是说回到就绪状态,当它再次获得CPU执行权的时候,会从 wait 方法的调用中返回,执行之后的语句。
4. 虚假的唤醒:线程线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防止它,如将wait放在循环中,苏醒后进入判断查看是否继续wait。
5. 中断interrupt:如果当前线程在等待之前或期间被任何线程中断,则抛出 InterruptedException。直到如上所述恢复此对象的锁定状态后,才会抛出此异常。
6. 此方法只能由作为此对象监视器的所有者的线程调用。 也就是说synchronized关键字修饰的地方。

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 >= 500000 || (nanos != 0 && timeout == 0)) {
        timeout++;
    }

    wait(timeout);
}

笑死我了,官方说这个方法是纳秒级对时间控制,笑拉了家人们,自欺欺人了属于是,哈哈哈哈。

public final void wait() throws InterruptedException {
    wait(0);
}

调用上面方法,当参数为0代表如果没人唤醒则永远等待。

public final native void notify();

唤醒在此对象的监视器上等待的单个线程。如果有任何线程正在等待该对象,则选择其中一个线程被唤醒。选择是任意的,并且由实现决定。线程通过调用等待方法之一在对象的监视器上等待。被唤醒的线程将无法继续,直到当前线程放弃对该对象的锁定。被唤醒的线程将以通常的方式与可能正在积极竞争以同步此对象的任何其他线程进行竞争;例如,被唤醒的线程在成为下一个锁定该对象的线程时没有可靠的特权或劣势。此方法只能由作为此对象监视器的所有者的线程调用。

线程通过以下三种方式之一成为对象监视器的所有者:

  1. 同步代码块
  2. 同步静态方法
  3. 同步非静态方法
public final native void notifyAll();

唤醒在此对象的监视器上等待的所有线程。

protected void finalize() throws Throwable { }

当垃圾收集器确定不再有对对象的引用时,由垃圾收集器在对象上调用。子类覆盖 finalize 方法以处理系统资源或执行其他清理。这里应该间接说明了垃圾回收线程维护着每个对象的引用,要不然对象没有引用不就丢了吗???还是说判断最后一个引用要消失的时候释放对象空间。暂时先不下定论,等过后我学习JVM的时候过来补。。。
这个方法在Object类中没有具体的实现,留给子类去重写。
注意finalize 方法抛出的任何异常都会导致此对象的终止被暂停,否则会被忽略。这会不会是内存泄漏的原因。。。

好啦,完结撒花★,°:.☆( ̄▽ ̄)/$:.°★

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值