在 Java 中 Object
類是全部類的祖先類,Object
沒有定義屬性,一共有13個方法。其它全部的子類都會繼承這些方法。java
private static native void registerNatives();
static {
registerNatives();
}
複製代碼
在 Java 中,用 native 關鍵字修飾的函數代表該方法的實現並非在Java中去完成,而是由C/C++去完成,並被編譯成了.dll,由Java去調用ios
而 registerNatives()
方法的主要做用則是將C/C++中的方法映射到 Java 中的 native
方法,實現方法命名的解耦。多線程
@HotSpotIntrinsicCandidate
public Object() {}
複製代碼
@HotSpotIntrinsicCandidate註解,該註解是特定於Java虛擬機的註解。經過該註解表示的方法可能( 但不保證 )經過HotSpot VM本身來寫彙編或IR編譯器來實現該方法以提供性能。 它表示註釋的方法可能(但不能保證)由HotSpot虛擬機內在化。若是HotSpot VM用手寫彙編和/或手寫編譯器IR(編譯器自己)替換註釋的方法以提升性能,則方法是內在的。 也就是說雖然外面看到的在JDK9中weakCompareAndSet和compareAndSet底層依舊是調用了同樣的代碼,可是不排除HotSpot VM會手動來實現weakCompareAndSet真正含義的功能的可能性函數
通常建立對象的時候直接使用 new className(Args)
來建立一個新的對象。而在類的定義過程當中,對於未定義構造函數的類,那麼它就會默認繼承Object
的無參構造函數,若是定了一個或多個構造函數,那麼就須要把無參構造函數方法也寫上。性能
@HotSpotIntrinsicCandidate
public final native Class<?> getClass();
複製代碼
getClass
返回運行時當前對象的類對象。在 Java 中,類是對具備一組相同特徵或行爲的實例的抽象進行描述。而類對象則是對類的特徵和行爲進行描述(即類的名稱,屬性,方法...)。也就是說經過獲取到類對象,則能夠獲取到該類的全部屬性,方法等。this
@HotSpotIntrinsicCandidate
public native int hashCode();
複製代碼
hashCode
返回當前對象的哈希碼。hashCode
遵照如下三個約定spa
hashCode
,那麼它們的返回值須要是一致的。(前提:沒有對對象進行修改)equals()
方法),那麼這兩個對象的 hashCode
也是同樣hashCode
方法返回的哈希碼相等,這兩個對象不必定相等也便是說,調用equals
方法返回值相等,那麼調用hashCode
方法返回值也必定相等。因此,在重寫euqlas
方法以後,必定要重寫hashCode
方法。.net
那麼判斷對象是否先等能夠直接用equals
來判斷,爲何還須要hashCode
方法呢?線程
其實hashCode
方法的一個主要做用是爲了加強哈希表的性能。好比:咱們知道Set
集合不能存在相同的兩個對象,那麼該怎麼判斷兩個對象是否相同呢?若是沒有hashCode
,那麼就須要進行遍從來逐一判斷。那麼有hashCode
,咱們就能夠計算出即將要加入集合的對象的hashCode
,而後查看集合中對應的位置上是否有對象便可。code
public boolean equals(Object obj) {
return (this == obj);
}
複製代碼
equals()
用於判斷兩個對象是否相等。根據 Object
的實現,能夠看到判斷的依據是看兩個對象的引用地址是否相等。
而通常咱們會用另一種方式來判斷是否相等。即==
,==
表示的是兩個變量值是否相等(基礎類型的值在內存地址中存儲的是值)
那麼咱們想要判斷是否相等:
==
來判斷equals
方法來判斷(在實際業務中,通常會重寫equals
方法)須要注意的一點是String
也是引用類型,咱們判斷String
的時候是直接使用的equals
方法,而按照默認的equals
實現,建立兩個具備相同值的String
對象,那麼equals
返回的應該是false
,
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
複製代碼
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
複製代碼
toString()
返回該對象的字符串表示。在使用 System.out.printLn(obj)
的時候,其內部也是調用的toString
方法。能夠按需重寫toString
方法。
protected native Object clone() throws CloneNotSupportedException;
複製代碼
clone()
方法返回的是當前對象的引用,指向的是新clone
出來的對象,此對象和原對象佔用不一樣的堆空間。
clone
方法的正確調用須要實現 cloneable
接口,若是沒有實現該接口,那麼子類調用父類的 clone
方法則會拋出CloneNotSupportedException
異常
Cloneable接口僅僅是一個表示接口,接口自己不包含任何方法,用來指示Object.clone()能夠合法的被子類引用所調用。
先看一段代碼
public class CloneTest {
public static void main(String[] args) {
Object o1 = new Object();
try {
Object clone = o1.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
複製代碼
執行這段段代碼會拋出The method clone() from the type Object is not visible
異常。緣由是clone
方法是被 protected
修飾的,也就是說被protected
修飾的屬性和方法,在同一包下或在不一樣包下的子類能夠訪問。顯然,CloneTest
和Object
不在同一包下,不過按照字面意思,CloneTest
會默認繼承Object
,因此即便在不一樣的包下,應該也是能夠訪問的纔對。那麼問題就出如今「在不一樣包下的子類能夠訪問」這句話上:
不一樣包中的子類能夠訪問: 是指當兩個類不在同一個包中的時候,繼承自父類的子類內部且主調(調用者)爲子類的引用時才能訪問父類用protected修飾的成員(屬性/方法)。 在子類內部,主調爲父類的引用時並不能訪問此protected修飾的成員。(super關鍵字除外)
也就是說在子類中想要調用父類的protected
方法,能夠
super.methodName()
來調用父類方法淺拷貝: 淺拷貝是按位拷貝對象,它會建立一個新對象,這個對象有着原始對象屬性值的一份精確拷貝。若是屬性是基本類型,拷貝的就是基本類型的值;若是屬性是引用類型,拷貝的就是內存地址。 深拷貝: 深拷貝會拷貝全部的屬性,並拷貝屬性指向的動態分配的內存。當對象和它所引用的對象一塊兒拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢而且花銷較大。
對於淺拷貝來講,若是含有引用類型,那麼修改其中一個對象的引用值,那麼會影響到另一個對象。按層級來講,淺拷貝只拷貝了第一層。對於默認的clone
實現是淺拷貝。若是想要實現深拷貝,能夠
clone
方法//序列化實現深拷貝
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//寫入字節流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配內存,寫入原始對象,生成新對象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新對象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
public class Person implements Serializable{
private static final long serialVersionUID = 2631590509760908280L;
}
public class CloneTest {
public static void main(String[] args) {
Person person = new Person();
Person person1 = CloneUtils.clone(person);
}
}
參考:https://blog.csdn.net/chenssy/article/details/12952063
複製代碼
protected void finalize() throws Throwable {}
複製代碼
finalize()
方法主要與 Java 垃圾回收機制有關,JVM準備對此對形象所佔用的內存空間進行垃圾回收前,將被調用。因此此方法並非由咱們主動去調用的。
可先看java 多線程嚐鮮。後續會專門講多線程相關源碼。