標籤:學習java java 程式設計 開發
Java作為一門優秀的物件導向的程式設計語言,正在被越來越多的人使用。在實際開發中碰到的一些Java語言的容易被人忽視的細節,下面分享一下希望能給正在學習Java語言的人有所協助。
1,位移運算越界怎麼處理
考察下面的代碼輸出結果是多少?
int a=5;
System.out.println(a<<33);
按照常理推測,把a左移33位應該將a的所有有效位都移出去了,那剩下的都是零啊,所以輸出結果應該是0才對啊,可是執行後發現輸出結果是10,為什麼呢?因為Java語言對位移運算作了最佳化處理,Java語言對a<轉化為a<<(b%32)來處理,所以當要移位的位元b超過32時,實際上移位的位元是b%32的值,那麼上面的代碼中a<<33相當於a<<1,所以輸出結果是10。
2,可以讓i!=i嗎?
當你看到這個命題的時候一定會以為我瘋了,或者Java語言瘋了。這看起來是絕對不可能的,一個數怎麼可能不等於它自己呢?或許就真的是Java語言瘋了,不信看下面的代碼輸出什嗎?
double i=0.0/0.0;
if(i==i){
System.out.println("Yes i==i");
}else{
System.out.println("No i!=i");
}
上面的代碼輸出"No i!=i",為什麼會這樣呢?關鍵在0.0/0.0這個值,在IEEE754浮點算術規則裡保留了一個特殊的值用來表示一個不是數位數量。這個值就是NaN("Not aNumber"的縮寫),對於所有沒有良好定義的浮點計算都將得到這個值,比如:0.0/0.0;其實我們還可以直接使用Double.NaN來得到這個值。在IEEE 754規範裡面規定NaN不等於任何值,包括它自己。所以就有了i!=i的代碼。
3,怎樣的equals才安全?
我們都知道在Java規範裡定義了equals方法覆蓋的5大原則:reflexive(反身性),symmetric(對稱性),transitive(傳遞性),consistent(一致性),non-null(非空性)。那麼考察下面的代碼:
public class Student{
private String name;
private int age;
public Student(String name,int age){
this.name=name;
this.age=age;
}
public boolean equals(Object obj){
if(obj instanceof Student){
Student s=(Student)obj;
if(s.name.equals(this.name) && s.age==this.age){
return true;
}
}
return super.equals(obj);
}
}
你認為上面的代碼equals方法的覆蓋安全嗎?表面看起來好像沒什麼問題,這樣寫也確實滿足了以上的五大原則。但其實這樣的覆蓋並不很安全,假如Student類還有一個子類CollegeStudent,如果我拿一個Student對象和一個CollegeStudent對象equals,只要這兩個對象有相同的name和age,它們就會被認為相等,但實際上它們是兩個不同類型的對象啊。問題就出在instanceof這個運算子上,因為這個運算子是向下相容的,也就是說一個CollegeStudent對象也被認為是一個Student的執行個體。怎樣去解決這個問題呢?那就只有不用instanceof運算子,而使用對象的getClass()方法來判斷兩個對象是否屬於同一種類型,例如,將上面的equals()方法修改為:
public boolean equals(Object obj){
if(obj.getClass()==Student.class){
Student s=(Student)obj;
if(s.name.equals(this.name) && s.age==this.age){
return true;
}
}
return super.equals(obj);
}
這樣才能保證obj對象一定是Student的執行個體,而不會是Student的任何子類的執行個體。
4,淺複製與深複製
1)淺複製與深複製概念
⑴淺複製(淺複製)
被複製對象的所有變數都含有與原來的對象相同的值,而所有的對其他對象的引用仍然指向原來的對象。換言之,淺複製僅僅複製所考慮的對象,而不複製它所引用的對象。
⑵深複製(深複製)
被複製對象的所有變數都含有與原來的對象相同的值,除去那些引用其他對象的變數。那些引用其他對象的變數將指向被複製過的新對象,而不再是原有的那些被引用的對象。換言之,深複製把要複製的對象所引用的對象都複製了一遍。
java細節,你注意到了多少?