Object
Object对象是Java中所有对象的父类 。一共有12个方法。源码如下(JDK1.8):
package java.lang;
public class Object {
public Object() {
}
//native方法
private static native void registerNatives();
//native方法
public final native Class<?> getClass();
//native方法
public native int hashCode();
public boolean equals(Object var1) {
return this == var1;
}
//native方法
protected native Object clone() throws CloneNotSupportedException;
public String toString() {
return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
}
//native方法
public final native void notify();
//native方法
public final native void notifyAll();
//native方法
public final native void wait(long var1) throws InterruptedException;
//wait() 需要被try catch包围,中断也可以使wait等待的线程唤醒。
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);
}
public final void wait() throws InterruptedException {
this.wait(0L);
}
protected void finalize() throws Throwable {
}
static {
registerNatives();
}
}
1. registerNatives
private static native void registerNatives();
static {
registerNatives();
}
registerNatives字面意思为注册本地服务,此方法为本地方法。
从Java1.1开始,JNI标准成为java平台的一部分,它允许Java代码和其他语言写的代码进行交互。
JNI是
Java Native Interface
的缩写,它提供了若干的API实现了Java和其他语言的通信(主要是C&C++)。
JNI一开始是为了本地已编译语言,尤其是C和C++而设计的,但是它并不妨碍你使用其他编程语言,只要调用约定受支持就可以了。
使用java与本地已编译的代码交互,通常会丧失平台可移植性。但是,有些情况下这样做是可以接受的,甚至是必须的。例如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI标准至少要保证本地代码能工作在任何Java 虚拟机环境。
2. getClass
获取类的实例的类对象(即Class对象)。同一个Class创建的所有对象实例,getClass()返回的对象相同。
3. hashCode
返回当前对象的哈希值,这个方法主要是为了hashTables相关功能而提供。这个值主要有以下特点:
- 在一个Java应用中,不管是你调用一次还是多次调用hashCode方法,此方法必须返回同一个hashCode,不能改变。但当在不同的Java应用时(不同的JVM进程),可以不相同。
- 如果两个对象调用equals方在一个Java应用中,不管是你调用一次还是多次调用hashCode方法,此方法必须返回同一个hashCode,不能改变。当在不同的Java应用时(不同的JVM进程),可以不相同。
-
如果x.equals(y)法返回true,那么这x,y这两个对象hashCode值一定相同。
-
两个不同对象(equals为false)产生的hash值不一定要求不能相等。可以有冲突相等。然而,开发者应该注意为了提高hash tables的性能,不同的对象产生的hashCode尽量不相等。
- 为了保证此方法尽可能的合理实现,hashCode通常通过Object对象来实现。最典型的实现就是将对象的内部地址转换为整数返回。 但是这个实现在Java语言中没有做强制要求。
4. equals
引用equals判断对象是否相等,可以扩展,根据实际情况来判断。
默认是判断hash值是否一样。即与 “==”算法一致。
但很多类进行自定义和扩展,因此不一致。
5. clone
克隆对象。具体使用时,需要实现CloneAble接口。此接口仅是一个标识接口,没有具体的方法。
package com.roboslyq.java.lang;
public class CloneTest {
public static void main(String[] args) {
ObjectTest objectTest1 = new ObjectTest();
objectTest1.setColunm1("你好");
ObjectTest objectTest;
{
try {
objectTest = objectTest1.clone();
//com.roboslyq.java.lang.ObjectTest@1540e19d
System.out.println(objectTest1.toString());
//com.roboslyq.java.lang.ObjectTest@677327b6
System.out.println(objectTest.toString());
// 此处打印为false,表明是一个新对象。。
System.out.println(objectTest1.equals(objectTest));
// 此处打印为true,表明是浅复制。即对象的引用对象只是复制了引用值,而不是复制具体的对象。
System.out.println(objectTest.getColunm1()
.equals(objectTest.getColunm1()));
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
}
class ObjectTest implements Cloneable{
private String colunm1;
private String colunm2;
public String getColunm1() {
return colunm1;
}
public void setColunm1(String colunm1) {
this.colunm1 = colunm1;
}
public String getColunm2() {
return colunm2;
}
public void setColunm2(String colunm2) {
this.colunm2 = colunm2;
}
public ObjectTest clone() throws CloneNotSupportedException
{
return (ObjectTest) super.clone();
}
}
打印一:com.roboslyq.java.lang.ObjectTest@1540e19d 打印二:com.roboslyq.java.lang.ObjectTest@677327b6 打印三:false
从打印一和二可知,clone之后是两个不同的对象。打印三也印证了这一点。
若要实现深拷贝,那么当前对象的中的所引用的对象,也要实现Cloneable
接口。然后在当前对象clone()
方法中调用相关对象的clone()
方法,然后赋值给当前对象的属性。
这种关系可以具体传递性(十分烦锁)。比如有四个对象A,B,C,D,D是C的一个属性,C是B的一个属性,B是A的一个属性。如:A –> B –>C –>D,那么A.clone要想完全实现深clone
,BC\D均需要实现clone接口,并且实现方式与A中深clone B对象实现一样。伪代码如下:
class A{
public A clone() throws CloneNotSupportedException
{
A newA = (A) super.clone();
B newB = this.B.clone();
newA.setB(newB);
return newA
}
}
6. toString
返回一个类的字符串描述。默认格式为”类名称” + “@” + “16进制的hashCode”。
例如:
com.roboslyq.java.lang.ObjectTest@1540e19d
7. notify
并发相关,本地final方法,无法被重写。通知等待当前对象的锁
8. notifyAll
并发相关,本地final方法,无法被重写。通知所有在等待当前对象的锁
notify/notifyAll配合wait方法使用。只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。
也就是说,notify/notifyAll() 的执行只是唤醒沉睡的线程,而不会立即释放锁,锁的释放要看代码块的具体执行情况。所以在编程中,尽量在使用了notify/notifyAll() 后立即退出临界区,以唤醒其他线程
9. wait系列
等待。此等待并不是没有获得锁,而是已经获得锁,然后因为需要的资源可能还没有准备不能继续往下执行。这时可以释放锁,让别的对象使用。
上锁解锁流程?
当线程执行wait()方法时候,会释放当前的锁,然后让出CPU,进入等待状态。
只有当 notify/notifyAll() 被执行时候,才会唤醒一个或多个正处于等待状态的线程,然后继续往下执行,直到执行完synchronized 代码块的代码或是中途遇到wait() ,再次释放锁。
9.1 wait()
无参wait,一直等待。直到被Interrupted
。
9.2 wait(long var1)
参数var1
为超时时间,单位为ms(milliseconds)。
9.3 wait(long timeout, int nanos)
参数timeout
为超时时间,单位为ms(milliseconds)。nanos单位为纳秒,值为0-999999
。
10. finalize
finalize,翻译过来是完成,使结束
的意思。在这里意指对象生命结束时进行的清理工作。但要注意,Java不像C一样开发人员完全掌控着内存的分配和回收,而是由JVM完全控制。所以finalize()和System.gc()方法都不一定靠得住 。这只是一个信号 ,具体是否真正进行回收由JVM GC根据内存情况决定 。
使用下面代码可以进行简单的测试。
package com.roboslyq.java.lang;
public class FinalizedTest {
public static void main(String[] args) {
new User();
System.gc();
}
}
class User{
@Override
public void finalize() throws Throwable {
super.finalize();
System.out.println("game over");
}
}
在大部分情况下,控制台会打印出game over
这个字符串。
底层C代码
#include <stdio.h>
#include <signal.h>
#include <limits.h>
#include "jni.h"
#include "jni_util.h"
#include "jvm.h"
#include "java_lang_Object.h"
static JNINativeMethod methods[] = {
{"hashCode", "()I", (void *)&JVM_IHashCode},
{"wait", "(J)V", (void *)&JVM_MonitorWait},
{"notify", "()V", (void *)&JVM_MonitorNotify},
{"notifyAll", "()V", (void *)&JVM_MonitorNotifyAll},
{"clone", "()Ljava/lang/Object;", (void *)&JVM_Clone},
};
JNIEXPORT void JNICALL
Java_java_lang_Object_registerNatives(JNIEnv *env, jclass cls)
{
(*env)->RegisterNatives(env, cls,
methods, sizeof(methods)/sizeof(methods[0]));
}
JNIEXPORT jclass JNICALL
Java_java_lang_Object_getClass(JNIEnv *env, jobject this)
{
if (this == NULL) {
JNU_ThrowNullPointerException(env, NULL);
return 0;
} else {
return (*env)->GetObjectClass(env, this);
}
}
版本:openjdk hotspot-8
Object.java对应的C语言源码路径
openjdk\jdk\src\share\native\java\lang\Object.c
。其中include "jvm.h"
在路径openjdk\jdk\src\share\javavm\export
下。
# 参考资料