Object類介紹
Object類位于java.lang包,是所有Java類的根父類(唯一沒有父類的類),所有類的直接或者間接父類。Java中的每個(gè)類都是由這個(gè)類擴(kuò)展而來(lái)。
java.lang包在使用的時(shí)候無(wú)需顯示導(dǎo)入,編譯時(shí)由編譯器自動(dòng)導(dǎo)入。
Java認(rèn)為所有的對(duì)象都具備一些基本的共性內(nèi)容,這些內(nèi)容可以不斷的向上抽取,最終就抽取到了一個(gè)最頂層的類中的,該類中定義的就是所有對(duì)象都具備的功能。
如果在類的聲明中未使用extends關(guān)鍵字指明其父類,則默認(rèn)父類為Object類。
public class Test [extends Object]{ // 默認(rèn)繼承了Object類
//...
}
接收任意引用類型的對(duì)象
既然Object類是所有對(duì)象的父類,則肯定所有的對(duì)象都可以向Object進(jìn)行轉(zhuǎn)換,在這其中也包含了數(shù)組和接口類型,即:一切的引用數(shù)據(jù)類型都可以使用Object進(jìn)行接收。
使用Object接收接口實(shí)例:
public class Test {
public static void main(String[] args) {
A ab = new B() ; // 為接口實(shí)例化
Object obj = ab ; // 對(duì)象向上轉(zhuǎn)型
A a = (A)obj ; // 對(duì)象向下轉(zhuǎn)型
a.print();
}
}
interface A { // 定義接口A
public void print() ; // 定義抽象方法
}
class B implements A { // 子類實(shí)現(xiàn)接口
public void print(){ // 覆寫接口中的抽象方法
System.out.println("test") ;
}
}
使用Object接收數(shù)組:
public class Test {
public static void main(String[] args) {
int[] array = {1, 3, 5, 7, 9} ; // 定義數(shù)組
Object obj = array ; // 使用Object接收數(shù)組
print(obj) ; // 傳遞數(shù)組引用
}
public static void print(Object o){ // 接收一個(gè)對(duì)象
if(o instanceof int[]) { // 判斷對(duì)象的類型
int x[] = (int[])o ; // 向下轉(zhuǎn)型
for(int i=0;i<x.length;i++){ // 循環(huán)輸出
System.out.print(x + "\t") ;
}
}
}
}
Object的主要方法
Object類中定義了一些有用的方法,由于是根類,所以這些方法都在其他類中存在,一般是進(jìn)行了重載或者覆蓋,實(shí)現(xiàn)了各自自己的具體功能。
public boolean equals(Object obj)
Object類中的equlas()方法用來(lái)檢測(cè)兩個(gè)對(duì)象是否等價(jià),查看Object源碼為:
public boolean equals(Object obj) {
return (this == obj);
}
equals()只能比較引用類型,其作用與“==”相同,比較是否指向同一個(gè)對(duì)象(其實(shí)內(nèi)部比較的就是兩個(gè)對(duì)象地址)。對(duì)象比較的是引用,即對(duì)象在內(nèi)存中的內(nèi)存地址,而基本數(shù)據(jù)類型比較的是值。
用“==”進(jìn)行比較時(shí),符號(hào)兩邊的數(shù)據(jù)類型必須兼容(可自動(dòng)轉(zhuǎn)換的基本數(shù)據(jù)類型除外),否則編譯出錯(cuò)。
equals()方法需要具有如下特點(diǎn):
自反性(reflexive):任何非空引用x,x.equals(x)返回為true。
對(duì)稱性(symmetric):任何非空引用x和y,x.equals(y)返回true當(dāng)且僅當(dāng)y.equals(x)返回true。
傳遞性(transitive):任何非空引用x和y,如果x.equals(y)返回true,并且y.equals(z)返回true,那么x.equals(z)返回true。
一致性(consistent):兩個(gè)非空引用x和y,x.equals(y)的多次調(diào)用應(yīng)該保持一致的結(jié)果,(前提條件是在多次比較之間沒有修改x和y用于比較的相關(guān)信息)。
約定:對(duì)于任何非空引用x,x.equals(null)應(yīng)該返回為false。
Student s1 = new Student();
Student s2 = new Student();
System.out.println(s1 == s2); // false
Student s3 = s1;
System.out.println(s3 == s1); // true
System.out.println(s1.equals(s2)); // false
System.out.println(s1.equals(s1)); // true
System.out.println(s1.equals(s3)); // true
當(dāng)用equals()方法進(jìn)行比較時(shí),對(duì)類File、String、Date及包裝類(Wrapper Class)來(lái)說(shuō),是比較類型及內(nèi)容而不考慮引用的是否是同一個(gè)對(duì)象;因?yàn)樵谶@些類中重寫了Object類的equals()方法。下面就是String重寫的equals()方法:
// 重寫了Object類中的equlas()方法
public boolean equals(Object anObject) {
// 判斷兩個(gè)字符串的內(nèi)存地址是否相等,如果相等,就說(shuō)明這兩個(gè)字符串是同一個(gè)
if (this == anObject) {
return true;
}
// 判斷參數(shù)對(duì)象是不是String類型的
if (anObject instanceof String) {
// 如果是,就向上轉(zhuǎn)型成一個(gè)String對(duì)象
String anotherString = (String)anObject;
// 對(duì)字符串逐個(gè)字符進(jìn)行比較,每個(gè)字符都相等,返回true
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1 != v2)
return false;
i++;
}
return true;
}
}
return false;
}
public int hashCode()
返回該對(duì)象的哈希碼值。哈希值是根據(jù)哈希算法計(jì)算出來(lái)的一個(gè)值。這個(gè)值和地址值有關(guān),但不是實(shí)際地址值。
該方法用于哈希查找,可以減少在查找中使用equals的次數(shù),重寫了equals方法一般都要重寫hashCode方法。這個(gè)方法在一些具有哈希功能的Collection中用到。
一般必須滿足obj1.equals(obj2)==true,可以推出obj1.hashCode()==obj2.hashCode(),但是hashCode相等不一定就滿足equals。不過為了提高效率,應(yīng)該盡量使上面兩個(gè)條件接近等價(jià)。如果不重寫hashcode(),在HashSet中添加兩個(gè)equals的對(duì)象,會(huì)將兩個(gè)對(duì)象都加入進(jìn)去。
// 對(duì)象不同,哈希值一般也不同
Student s1 = new Student();
System.out.println(s1.hashCode()); // 366712642
Student s2 = new Student();
System.out.println(s2.hashCode()); // 1829164700
System.out.println("-------");
public final Class getClass()
返回Object運(yùn)行時(shí)類,也就是說(shuō)是字節(jié)碼文件對(duì)象。
不可重寫,要調(diào)用的話,一般和getName()聯(lián)合使用,如getClass().getName()。
Student s = new Student();
// getClass方法會(huì)返回一個(gè)Class類的實(shí)例對(duì)象,然后調(diào)用Class類的getName()方法返回全路徑名
System.out.println(s.getClass().getName()); // com.zwj.objectdemo.Student
public String toString()
Object 類的 toString 方法返回一個(gè)字符串,該字符串由類名(對(duì)象是該類的一個(gè)實(shí)例)、at 標(biāo)記符“@”和此對(duì)象哈希碼的無(wú)符號(hào)十六進(jìn)制表示組成。換句話說(shuō),該方法返回一個(gè)字符串,它的值等于: getClass().getName() + ‘@’ + Integer.toHexString(hashCode())
// toString方法:返回對(duì)象的字符串表示
System.out.println(s.toString()); // com.zwj.objectdemo.Student@7852e922
//直接輸出對(duì)象的名稱其實(shí)就是調(diào)用了對(duì)象的toString方法
System.out.println(s); //com.zwj.objectdemo.Student@7852e922
protected void finalize()
當(dāng)垃圾回收器確定不存在對(duì)該對(duì)象的更多引用時(shí),由對(duì)象的垃圾回收器調(diào)用此方法,用于垃圾回收。但是具體什么時(shí)間調(diào)用此方法不確定。
Java允許在類中定義一個(gè)名為finalize()的方法。它的工作原理是:一旦垃圾回收器準(zhǔn)備好釋放對(duì)象占用的存儲(chǔ)空間,將首先調(diào)用其finalize()方法。并且在下一次垃圾回收動(dòng)作發(fā)生時(shí),才會(huì)真正回收對(duì)象占用的內(nèi)存。
關(guān)于垃圾回收,有三點(diǎn)需要記住:
1)對(duì)象可能不被垃圾回收。只要程序沒有瀕臨存儲(chǔ)空間用完的那一刻,對(duì)象占用的空間就總也得不到釋放。
2)垃圾回收并不等于“析構(gòu)”。
3)垃圾回收只與內(nèi)存有關(guān)。使用垃圾回收的唯一原因是為了回收程序不再使用的內(nèi)存。
finalize()的用途:
無(wú)論對(duì)象是如何創(chuàng)建的,垃圾回收器都會(huì)負(fù)責(zé)釋放對(duì)象占據(jù)的所有內(nèi)存。這就將對(duì)finalize()的需求限制到一種特殊情況,即通過某種創(chuàng)建對(duì)象方式以外的方式為對(duì)象分配了存儲(chǔ)空間。
不過這種情況一般發(fā)生在使用“本地方法”的情況下,本地方法是一種在Java中調(diào)用非Java代碼的方式。
protected Object clone()
創(chuàng)建并返回此對(duì)象的一個(gè)副本,需要重寫該方法。
要克隆的類去實(shí)現(xiàn)Cloneable接口 ,Cloneable接口是標(biāo)記接口,實(shí)現(xiàn)該接口的類就可以實(shí)現(xiàn)對(duì)象的復(fù)制。
public class Student implements Cloneable{
private String name; // 姓名
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
我們來(lái)測(cè)試一下:
public class StudentTest{
public static void main(String[] args) throws CloneNotSupportedException {
// 創(chuàng)建顯示對(duì)象
Student s = new Student();
s.setName("zwj");
// 克隆學(xué)生對(duì)象
Student cloneStu = (Student) s.clone();
// 引用
Student s2 = s;
System.out.println(s.getName()); // zwj,
System.out.println(cloneStu.getName()); // zwj
System.out.println(s2.getName()); // zwj
s2.setName("爪哇菌");
System.out.println(s.getName()); // 爪哇菌
System.out.println(cloneStu.getName()); // zwj
System.out.println(s2.getName()); // 爪哇菌
}
}
由以上代碼代碼可以看出Clone()方法的使用比較簡(jiǎn)單,使用時(shí)注意如下幾點(diǎn)即可:
什么時(shí)候使用shallow Clone,什么時(shí)候使用deep Clone,這個(gè)主要看具體對(duì)象的域是什么性質(zhì)的,基本型別還是reference variable。
調(diào)用Clone()方法的對(duì)象所屬的類必須實(shí)現(xiàn)(implements )Clonable接口,否則在調(diào)用Clone方法的時(shí)候會(huì)拋出CloneNotSupportedException。
---------------------
【轉(zhuǎn)載】
作者:下班后的爪哇菌
原文:https://blog.csdn.net/lxxiang1/a ... 874?utm_source=copy
本文版權(quán)歸黑馬程序員JavaEE培訓(xùn)學(xué)院所有,歡迎轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)注明作者出處。謝謝!
作者:黑馬程序員JavaEE培訓(xùn)學(xué)院
首發(fā):http://java.itcast.cn/?skc