jdk1.4和jdk1.5的有那些區別
2 自動裝箱/拆箱
3 for-each
4 static import
5 變長引數[@more@]
1. 泛型 1.4之前 java util包中容器類,裝的是Object物件,你要裝特定的型別可以,但要強制轉換,這可能導致執行時錯誤.
例:原來ArrayList list=new ArrayList();
list.add(new Integer(3));
list.add(new Integer(4));
int i=((Integer)(list.get(0))).parseInt();
很麻煩
現在ArrayList
list.add(new Integer(3));
list.add(new Integer(4));
int i=list.get(0).parseInt();
不用Cast,執行時錯誤變為編譯時錯誤,這是進步.
類似與C++中的摸板templete.但機理不同.
2 自動裝箱/拆箱
還是剛才例子
最後一句可改為
int i=list.get(0);
原始型別與對應的包裝類不用顯式轉換,方便
3 for-each
迴圈的增強
int a[]={........};//初始化,略
for(int i:a)
{
......
}
不用以前的i=0;i
以前調Java.math
Math.sqrt();
現在 static import java.lang.Math.sqrt;
再 sqrt();
相當於你自己類裡有這個方法
5 變長引數
int sum(int ...intlist)
{
int i,sum;
sum=0;
for(int i=0;i
sum+=list[i];
}
return sum;
}
有任意個引數,把他看作陣列
沒多大區別,只要你注意別用那些過時的方法就行,若是新版本加的或有改變的方法,docs裡會說的,在方法解釋下面
jdk6.0將會有很大變化
增強的for迴圈
為了迭代集合和陣列,增強的for迴圈提供了一個簡單、相容的語法。有兩點值得一提:
Init表示式
在迴圈中,初始化表示式只計算一次。這意味著您通常可以移除一個變數宣告。在這個例子中,我們必須建立一個整型陣列來儲存computeNumbers()的結果,以防止每一次迴圈都重新計算該方法。您可以看到,下面的程式碼要比上面的程式碼整潔一些,並且沒有洩露變數numbers:
未增強的For:
int sum = 0;
Integer[] numbers = computeNumbers();
for (int i=0; i < numbers.length ; i++)
sum += numbers[i];
增強後的For:
int sum = 0;
for ( int number: computeNumbers() )
sum += number;
侷限性
有時需要在迭代期間訪問迭代器或下標,看起來增強的for迴圈應該允許該操作,但事實上不是這樣,請看下面的例子:
for (int i=0; i < numbers.length ; i++) {
if (i != 0) System.out.print(",");
System.out.print(numbers[i]);
}
我們希望將陣列中的值列印為一個用逗號分隔的清單。我們需要知道目前是否是第一項,以便確定是否應該列印逗號。使用增強的for迴圈是無法獲知這種資訊的。我們需要自己保留一個下標或一個布林值來指示是否經過了第一項。 這是另一個例子:
for (Iterator
if (it.next() < 0)
it.remove();
在此例中,我們想從整數集合中刪除負數項。為此,需要對迭代器呼叫一個方法,但是當使用增強的for 迴圈時,迭代器對我們來說是看不到的。因此,我們只能使用Java 5之前版本的迭代方法。 順便說一下,這裡需要注意的是,由於Iterator是泛型,所以其宣告是Iterator
註釋
註釋處理是一個很大的話題。因為本文只關注核心的語言特性,所以我們不打算涵蓋它所有的可能形式和陷阱。 我們將討論內建的註釋(SuppressWarnings,Deprecated和Override)以及一般註釋處理的侷限性。
Suppress Warnings
該註釋關閉了類或方法級別的編譯器警告。有時候您比編譯器更清楚地知道,程式碼必須使用一個被否決的方法或執行一些無法靜態確定是否型別安全的動作,而使用:
@SuppressWarnings("deprecation")
public static void selfDestruct() {
Thread.currentThread().stop();
}
這可能是內建註釋最有用的地方。遺憾的是,1.5.0_04的javac不支援它。但是1.6支援它,並且Sun正在努力將其向後移植到1.5中。
Eclipse 3.1中支援該註釋,其他IDE也可能支援它。這允許您把程式碼徹底地從警告中解脫出來。如果在編譯時出現警告,可以確定是您剛剛把它新增進來——以幫助檢視那些可能不安全的程式碼。隨著泛型的新增,它使用起來將更趁手。
Deprecated
遺憾的是,Deprecated沒那麼有用。它本來旨在替換@deprecated javadoc標籤,但是由於它不包含任何欄位,所以也就沒有方法來建議deprecated類或方法的使用者應該使用什麼做為替代品。大多數用法都同時需要javadoc標籤和這個註釋。
Override
Override表示,它所註釋的方法應該重寫超類中具有相同簽名的方法:
@Override
public int hashCode() {
...
}
看上面的例子,如果沒有在hashCode中將“C”大寫,在編譯時不會出現錯誤,但是在執行時將無法像期望的那樣呼叫該方法。透過新增Override標籤,編譯器會提示它是否真正地執行了重寫。
在超類發生改變的情況中,這也很有幫助。如果向該方法中新增一個新引數,而且方法本身也被重新命名了,那麼子類將突然不能編譯,因為它不再重寫超類的任何東西。
其它註釋
註釋在其他場景中非常有用。當不是直接修改行為而是增強行為時,特別是在新增樣板程式碼的情況下,註釋在諸如EJB和Web services這樣的框架中執行得非常好。
註釋不能用做前處理器。Sun的設計特別預防了完全因為註釋而修改類的位元組碼。這樣可以正確地理解該語言的成果,而且IDE之類的工具也可以執行深入的程式碼分析和重構之類的功能。
註釋不是銀彈。第一次遇到的時候,人們試圖嘗試各種技巧。請看下面這個從別人那裡獲得的建議:
public class Foo {
@Property
private int bar;
}
其思想是為私有欄位bar自動建立getter和setter方法。遺憾的是,這個想法有兩個失敗之處:1)它不能執行,2)它使程式碼難以閱讀和處理。 它是無法實現的,因為前面已經提到了,Sun特別阻止了對出現註釋的類進行修改。
即使是可能的,它也不是一個好主意,因為它使程式碼可讀性差。第一次看到這段程式碼的人會不知道該註釋建立了方法。此外,如果將來您需要在這些方法內部執行一些操作,註釋也是沒用的。 總之,不要試圖用註釋去做那些常規程式碼可以完成的事情。
列舉
enum非常像public static final int宣告,後者作為列舉值已經使用了很多年。對int所做的最大也是最明顯的改進是型別安全——您不能錯誤地用列舉的一種型別代替另一種型別,這一點和int不同,所有的int對編譯器來說都是一樣的。除去極少數例外的情況,通常都應該用enum例項替換全部的列舉風格的int結構。
列舉提供了一些附加的特性。EnumMap和EnumSet這兩個實用類是專門為列舉最佳化的標準集合實現。如果知道集合只包含列舉型別,那麼應該使用這些專門的集合來代替HashMap或HashSet。
大部分情況下,可以使用enum對程式碼中的所有public static final int做插入替換。它們是可比的,並且可以靜態匯入,所以對它們的引用看起來是等同的,即使是對於內部類(或內部列舉型別)。注意,比較列舉型別的時候,宣告它們的指令表明了它們的順序值。
“隱藏的”靜態方法
兩個靜態方法出現在所有列舉型別宣告中。因為它們是列舉子類上的靜態方法,而不是Enum本身的方法,所以它們在java.lang.Enum的javadoc中沒有出現。
第一個是values(),返回一個列舉型別所有可能值的陣列。
第二個是valueOf(),為提供的字串返回一個列舉型別,該列舉型別必須精確地匹配原始碼宣告。
方法
關於列舉型別,我們最喜歡的一個方面是它可以有方法。過去您可能需要編寫一些程式碼,對public static final int進行轉換,把它從資料庫型別轉換為JDBC URL。而現在則可以讓列舉型別本身帶一個整理程式碼的方法。下面就是一個例子,包括DatabaseType列舉型別的抽象方法以及每個列舉例項中提供的實現:
public enum DatabaseType {
ORACLE {
public String getJdbcUrl() {...}
},
MYSQL {
public String getJdbcUrl() {...}
};
public abstract String getJdbcUrl();
}
現在列舉型別可以直接提供它的實用方法。例如:
DatabaseType dbType = ...;
String jdbcURL = dbType.getJdbcUrl();
要獲取URL,必須預先知道該實用方法在哪裡。
可變引數(Vararg)
正確地使用可變引數確實可以清理一些垃圾程式碼。典型的例子是一個帶有可變的String引數個數的log方法:
Log.log(String code)
Log.log(String code, String arg)
Log.log(String code, String arg1, String arg2)
Log.log(String code, String[] args)
當討論可變引數時,比較有趣的是,如果用新的可變引數替換前四個例子,將是相容的:
Log.log(String code, String... args)
所有的可變引數都是源相容的——那就是說,如果重新編譯log()方法的所有呼叫程式,可以直接替換全部的四個方法。然而,如果需要向後的二進位制相容性,那麼就需要捨去前三個方法。只有最後那個帶一個字串陣列引數的方法等效於可變引數版本,因此可以被可變引數版本替換。
型別強制轉換
如果希望呼叫程式瞭解應該使用哪種型別的引數,那麼應該避免用可變引數進行型別強制轉換。看下面這個例子,第一項希望是String,第二項希望是Exception:
Log.log(Object... objects) {
String message = (String)objects[0];
if (objects.length > 1) {
Exception e = (Exception)objects[1];
// Do something with the exception
}
}
方法簽名應該如下所示,相應的可變引數分別使用String和Exception宣告:
Log.log(String message, Exception e, Object... objects) {...}
不要使用可變引數破壞型別系統。需要強型別化時才可以使用它。對於這個規則,PrintStream.printf()是一個有趣的例外:它提供型別資訊作為自己的第一個引數,以便稍後可以接受那些型別。
協變返回
協變返回的基本用法是用於在已知一個實現的返回型別比API更具體的時候避免進行型別強制轉換。在下面這個例子中,有一個返回Animal物件的Zoo介面。我們的實現返回一個AnimalImpl物件,但是在JDK 1.5之前,要返回一個Animal物件就必須宣告。:
public interface Zoo {
public Animal getAnimal();
}
public class ZooImpl implements Zoo {
public Animal getAnimal(){
return new AnimalImpl();
}
}
協變返回的使用替換了三個反模式:
直接欄位訪問。為了規避API限制,一些實現把子類直接暴露為欄位:
ZooImpl._animal
另一種形式是,在知道實現的實際上是特定的子類的情況下,在呼叫程式中執行向下轉換:
((AnimalImpl)ZooImpl.getAnimal()).implMethod();
我看到的最後一種形式是一個具體的方法,該方法用來避免由一個完全不同的簽名所引發的問題:
ZooImpl._getAnimal();
這三種模式都有它們的問題和侷限性。要麼是不夠整潔,要麼就是暴露了不必要的實現細節。
協變
協變返回模式就比較整潔、安全並且易於維護,它也不需要型別強制轉換或特定的方法或欄位:
public AnimalImpl getAnimal(){
return new AnimalImpl();
}
使用結果:
ZooImpl.getAnimal().implMethod();
使用泛型
我們將從兩個角度來了解泛型:使用泛型和構造泛型。我們不討論List、Set和Map的顯而易見的用法。知道泛型集合是強大的並且應該經常使用就足夠了。
我們將討論泛型方法的使用以及編譯器推斷型別的方法。通常這些都不會出問題,但是當出問題時,錯誤資訊會非常令人費解,所以需要了解如何修復這些問題。
泛型方法
除了泛型型別,Java 5還引入了泛型方法。在這個來自java.util.Collections的例子中,構造了一個單元素列表。新的List的元素型別是根據傳入方法的物件的型別來推斷的:
static
示例用法:
public List
return Collections.singletonList(1);
}
在示例用法中,我們傳入了一個int。所以方法的返回型別就是List
這也顯示了自動裝箱和泛型的相互作用。型別引數必須是引用型別:這就是為什麼我們得到的是List
不帶引數的泛型方法
emptyList()方法與泛型一起引入,作為java.util.Collections中EMPTY_LIST欄位的型別安全置換:
static
示例用法:
public List
return Collections.emptyList();
}
與先前的例子不同,這個方法沒有引數,那麼編譯器如何推斷T的型別呢?基本上,它將嘗試使用一次引數。如果沒有起作用,它再次嘗試使用返回或賦值型別。在本例中,返回的是List
如果在返回語句或賦值語句之外的位置呼叫泛型方法會怎麼樣呢?那麼編譯器將無法執行型別推斷的第二次傳送。在下面這個例子中,emptyList()是從條件運算子內部呼叫的:
public List
return x ? Collections.emptyList() : null;
}
因為編譯器看不到返回上下文,也不能推斷T,所以它放棄並採用Object。您將看到一個錯誤訊息,比如:“無法將List
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/219138/viewspace-913912/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- htmlentities和htmlspecialchars 的區別有哪些HTML
- python中json.dump() 和 json.dumps() 有那些區別?PythonJSON
- HTTP和HTTPS的區別有哪些?HTTP
- SQLSERVER 的 truncate 和 delete 有區別嗎?SQLServerdelete
- require和import有啥區別?UIImport
- Struct 和 Union有下列區別Struct
- *和body有什麼區別
- @Autowired和@Resource有哪些區別
- IPFS和區塊鏈有什麼區別區塊鏈
- CEO 和 CTO 沒有本質的區別
- python堆和棧的區別有哪些Python
- window.eval()和eval()是有區別的
- 有狀態和無狀態的區別
- Cache 和 Buffer 有什麼區別?
- HTTP和HTTPS有哪些區別?HTTP
- mongodb和mysql有什麼區別MongoDBMySql
- shim和polyfill有什麼區別
- float和double有什麼區別?
- int 和 Integer 有什麼區別
- cookie和session 有什麼區別?CookieSession
- session 和 cookie 有什麼區別?SessionCookie
- modbus和tcp有什麼區別?TCP
- Nginx和Apache有什麼區別?NginxApache
- COOKIE和SESSION有什麼區別?CookieSession
- RegisterClass和RegisterClassEx有什麼區別?
- for update 和 for update of 有什麼區別
- PEAR 和 PECL 有什麼區別?
- Activity和Fragment有什麼區別Fragment
- vue和react有什麼區別?VueReact
- Iterator和ListIterator有什麼區別
- Hifi和ONT 有什麼區別
- DOM和BOM有什麼區別?
- 好程式設計師雲端計算教程分享雲服務和雲端計算的區別有那些程式設計師
- 天正軟體和cad有什麼區別 天正建築和cad的區別
- WPF中的StaticResource和DynamicResource有什麼區別
- python的模組和類有什麼區別Python
- mysql的having和where有什麼區別MySql
- HTTP和HTTPS有什麼主要的區別?HTTP