一、clone
- 淺克虑ζァ:創(chuàng)建一個(gè)新對(duì)象押赊,新對(duì)象的屬性和原來對(duì)象完全相同,對(duì)于非基本類型屬性,仍指向原有屬性所指向的對(duì)象的內(nèi)存地址流礁。
- 深克绿樗住:創(chuàng)建一個(gè)新對(duì)象,屬性中引用的其他對(duì)象也會(huì)被克隆神帅,不再指向原有對(duì)象地址再姑。
總之深淺克隆都會(huì)在堆中新分配一塊區(qū)域,區(qū)別在于對(duì)象屬性引用的對(duì)象是否需要進(jìn)行克抡矣(遞歸性的)元镀。
case:
public class Main {
public static void main(String[] args) {
// 創(chuàng)建父親(LiSi),兒子(LiWu)霎桅,孫子(LiLiu)并關(guān)聯(lián)
Son father = new Son();
father.setName("LiSi");
Son son = new Son();
son.setName("LiWu");
Son grandSon = new Son();
grandSon.setName("LiLiu");
father.setSon(son);
son.setSon(grandSon);
// 調(diào)用clone方法
Son fatherCopy = null;
try {
fatherCopy = (Son) father.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
boolean flag1 = fatherCopy==father;
boolean flag2 = fatherCopy.getSon() == son;
boolean flag3 = fatherCopy.getSon().getSon() == grandSon;
// 比較克隆后的地址
System.out.println(flag1);// false
System.out.println(flag2);// true
System.out.println(flag3);// true
// 比較Name
flag1= fatherCopy.getName()==father.getName();
flag2 = fatherCopy.getSon().getName() == son.getName();
flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();
System.out.println(flag1);// true
System.out.println(flag2);// true
System.out.println(flag3);// true
}
}
如上栖疑,如果對(duì)象實(shí)現(xiàn)Cloneable并重寫clone方法不進(jìn)行任何操作時(shí),調(diào)用clone是進(jìn)行的淺克隆。
既然實(shí)現(xiàn)Cloneable接口并重寫clone接口只能進(jìn)行淺克隆滔驶。但是如果類的引用類型屬性(以及屬性的引用類型屬性)都進(jìn)行淺克隆遇革,直到?jīng)]有引用類型屬性或者引用類型屬性為null時(shí),整體上就形成了深克隆揭糕。既對(duì)象的引用類型屬性和屬性的應(yīng)用類型屬性都實(shí)現(xiàn)Coloneable萝快,重寫clone方法并在clone方法中進(jìn)行調(diào)用。
protected Object clone() throws CloneNotSupportedException {
Son result = (Son) super.clone();
if (son != null) {
result.son = (Son) son.clone();
}
return result;
}
二插佛、equals and hashCode
equals
equals 方法既然是基類 Object 的方法,我們創(chuàng)建的所有的對(duì)象都擁有這個(gè)方法量窘,并有權(quán)利去重寫這個(gè)方法雇寇。該方法返回一個(gè) boolean 值,代表比較的兩個(gè)對(duì)象是否相同蚌铜,這里的相同的條件由重寫 equals 方法的類來解決锨侯。
String str1 = "abc";
String str2 = "abc";
str1.equals(str2);//true
顯然 String 類一定重寫了 equals 方法否則兩個(gè) String 對(duì)象內(nèi)存地址肯定不同。
public boolean equals(Object anObject) {
//首先判斷兩個(gè)對(duì)象的內(nèi)存地址是否相同
if (this == anObject) {
return true;
}
// 判斷連個(gè)對(duì)象是否屬于同一類型冬殃。
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
//長(zhǎng)度相同的情況下逐一比較 char 數(shù)組中的每個(gè)元素是否相同
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;}
hashCode
hashCode()定義在JDK的Object.java中囚痴,這就意味著Java中的任何類都包含有hashCode() 函數(shù)。
hashCode()的作用是獲取hash值审葬,也稱為散列碼深滚;它實(shí)際上是返回一個(gè)int整數(shù)。這個(gè)hash值的作用是確定該對(duì)象在哈希表中的索引位置涣觉。也就是說hash值要在一些數(shù)據(jù)結(jié)構(gòu)中才能顯現(xiàn)作用痴荐。hashcode一般用在hashmap、hashset里官册,判斷要把數(shù)據(jù)放在數(shù)組的什么位置生兆。
下面,我們以HashSet為例膝宁,來深入說明hashCode()的作用鸦难。
假設(shè)根吁,HashSet中已經(jīng)有1000個(gè)元素。當(dāng)插入第1001個(gè)元素時(shí)合蔽,需要怎么處理击敌?因?yàn)镠ashSet是Set集合,它不允許有重復(fù)元素辈末。 “將第1001個(gè)元素逐個(gè)的和前面1000個(gè)元素進(jìn)行比較”愚争?顯然,這個(gè)效率是相等低下的挤聘。散列表很好的解決了這個(gè)問題轰枝,它根據(jù)元素的散列碼計(jì)算出元素在散列表中的位置,然后將元素插入該位置即可组去。對(duì)于相同的元素鞍陨,自然是只保存了一個(gè)。 由此可知从隆,若兩個(gè)對(duì)象相等诚撵,它們的散列碼一定相等;但反過來不一定键闺。在散列表中寿烟,
1、如果兩個(gè)對(duì)象相等辛燥,那么它們的hashCode()值一定要相同筛武。這里的相等是指,通過equals()比較兩個(gè)對(duì)象時(shí)返回true挎塌。
2徘六、如果兩個(gè)對(duì)象hashCode()相等,它們并不一定相等榴都。
轉(zhuǎn)自:http://www.reibang.com/p/cf164837f8ed
三待锈、getClass
getClass方法是獲得Class對(duì)象的方法之一
class A{
public void func(){
}
}
public class Test {
public static void main(String[] args) {
A a = new A();
System.out.println(a.getClass()); // class A
}
}
反射學(xué)習(xí)
所謂反射,可以理解為在運(yùn)行時(shí)期獲取對(duì)象類型信息的操作嘴高。傳統(tǒng)的編程方法要求程序員在編譯階段決定使用的類型竿音,但是在反射的幫助下,編程人員可以動(dòng)態(tài)獲取這些信息拴驮,從而編寫更加具有可移植性的代碼谍失。嚴(yán)格地說,反射并非編程語言的特性莹汤,因?yàn)樵谌魏我环N語言都可以實(shí)現(xiàn)反射機(jī)制快鱼,但是如果編程語言本身支持反射,那么反射的實(shí)現(xiàn)就會(huì)方便很多。
Java反射機(jī)制主要提供了以下功能: 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類抹竹;在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象线罕;在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法;在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法窃判;生成動(dòng)態(tài)代理钞楼。
補(bǔ)充:獲取class對(duì)象的三種方式
- 使用forName()方法:
Class<?> clazz = Class.forName(className);
- 調(diào)用屬性:
Class<?> clazz = Person.class;
- 利用對(duì)象調(diào)用Object的getClass方法
Person p = new Person(); Class<?> clazz = p.getClass();
四、toString
toString()是Object類的一個(gè)公有方法袄琳,而所有類都繼承自O(shè)bject類询件。所以所有類即使不實(shí)現(xiàn)toString方法,也會(huì)存在從Object類繼承來的toString唆樊。
類可以實(shí)現(xiàn)toString方法宛琅,在控制臺(tái)中打印一個(gè)對(duì)象會(huì)自動(dòng)調(diào)用對(duì)象類的toString方法。打印的是對(duì)象名 + @換為十六進(jìn)制的對(duì)象的哈希值
public class Test {
public static void main(String[] args){
Car car1 = new Car("寶馬",300000.00);
Car car2 = new Car("奔馳",500000.00);
System.out.println(car1); // Car@4554617c
System.out.println(car2); // Car@74a14482
}
}
我們也可以實(shí)現(xiàn)自己從寫toString方法在控制臺(tái)中顯示關(guān)于類的有用信息逗旁。
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
// 再次運(yùn)行上面的Test代碼得
// Car{name='寶馬', price=300000.0}
// Car{name='奔馳', price=500000.0}
八種基本數(shù)據(jù)類型沒有toString()方法嘿辟,只能使用相應(yīng)的包裝類才能使用toString()。