jdk5.0新特性
您也許已經(jīng)見過這樣的報告,即一些新的 Java 語言變化包含易于開發(fā)性主題。這些變化包括泛型、元數(shù)據(jù)、autoboxing、增強的 for 循環(huán)、枚舉類型、靜態(tài)導(dǎo)入、C 風(fēng)格的格式化 I/O、可變參數(shù)、并發(fā)實用程序以及更簡單的 RMI 接口生成。JSR 201 包括如下四個語言變化:增強的 for 循環(huán)、枚舉類型、靜態(tài)導(dǎo)入和 autoboxing;JSR 175 指定了新的元數(shù)據(jù)功能,而 JSR 14 則詳細(xì)說明了泛型。
javac 編譯器執(zhí)行的默認(rèn)語言規(guī)范是版本 1.4。這意味著要利用以下語言變化的任何好處,需要向 javac 命令傳遞參數(shù) -source 1.5。
元數(shù)據(jù)
J2SE 1.5 中的元數(shù)據(jù)特性提供這樣的能力,即向 Java 類、接口、方法和字段關(guān)聯(lián)附加的數(shù)據(jù)。這些附加的數(shù)據(jù)或者注釋,可以被 javac 編譯器或其他工具讀取,并且根據(jù)配置不同,可以被保存在類文件中,也可以在運行時使用 Java 反射 API 被發(fā)現(xiàn)。
向 Java 平臺增加元數(shù)據(jù)的一個主要原因是,使得開發(fā)工具和運行工具有一個通用的基礎(chǔ)結(jié)構(gòu),以減少開發(fā)和部署所需的成本。工具可以使用元數(shù)據(jù)信息生成附加的源代碼,或者在調(diào)試時提供附加信息。
下面的例子用元數(shù)據(jù)工具創(chuàng)建了一個調(diào)試元數(shù)據(jù)注釋,這些元數(shù)據(jù)注釋然后又簡單地在運行時顯示出來??梢韵胂?,大部分的元數(shù)據(jù)標(biāo)簽形成一個標(biāo)準(zhǔn),即一個良好規(guī)范的集合。
import java.lang.annotation.*;
import java.lang.reflect.*;
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @interface debug {
boolean devbuild() default false;
int counter();
}
public class MetaTest {
final boolean production=true;
@debug(devbuild=production,counter=1) public void testMethod() {
}
public static void main(String[] args) {
MetaTest mt = new MetaTest();
try {
Annotation[] a = mt.getClass().getMethod("testMethod").getAnnotations();
for (int i=0; i<a.length ; i++) {
System.out.println("a["+i+"]="+a+" ");
}
} catch(NoSuchMethodException e) {
System.out.println(e);
}
}
}
利用一個元數(shù)據(jù)處理工具,許多重復(fù)的代碼編寫步驟可以減少成一個簡練的元數(shù)據(jù)標(biāo)簽。例如,訪問某個 JAX-RPC 服務(wù)實現(xiàn)時所需的遠(yuǎn)程接口可以實現(xiàn)為:
原來(J2SE 1.5 以前版本):
public interface PingIF extends Remote {
public void ping() throws RemoteException;
}
public class Ping implements PingIF {
public void ping() {
}
}
現(xiàn)在:
public class Ping {
public @remote void ping() {
}
}
范型
范型一直是 Java 社團(tuán)所廣泛期待的,現(xiàn)在已經(jīng)是 J2SE 1.5 的一部分了。最先見到使用泛型的地方是在 Collections API 中。Collections API 提供可以被多個 Java 類型使用的公共功能性,比如 LinkedLists、ArrayLists 和 HashMaps。下一個例子使用 1.4.2 庫和默認(rèn)的 javac 編譯模式。
ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = ((Integer)list.get(0)).intValue();
最后一行中的 Integer 轉(zhuǎn)換是泛型所要防止的強制類型轉(zhuǎn)換問題的一個例子。這個問題在于,1.4.2 Collections API 使用 Object 類來存儲 Collection 對象,這就意味著在編譯的時候不能找出類型匹配。問題的第一個標(biāo)志信息是在運行時拋出的 ClassCastException。
帶有范型化 Collections 庫的同一個例子可編寫為:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = list.get(0).intValue();
范型化 API 的用戶必須使用 <> 符號簡單地聲明在編譯類型中使用的類型。不需要任何類型轉(zhuǎn)換,在本例中試圖向一個 Integer 類型的集合中添加 String 對象將會在編譯時被捕獲。
因此,范型允許 API 設(shè)計者提供這樣的公共功能性:可以與多種數(shù)據(jù)類型一起使用,也可以在編譯時出于類型安全對它進(jìn)行檢查。
設(shè)計自己的 Generic API 比起只是使用它們來說要稍微復(fù)雜一些。請從查看 java.util.Collection 源代碼和 API 指南開始。
原語類型的 Autoboxing 和 Auto-unboxing
像 int、boolean 以及它們的基于對象的對應(yīng)物(比如 Integer 和 Boolean)這樣的原語類型之間的轉(zhuǎn)換需要大量不必要的額外編碼, 尤其是當(dāng)只是像 Collections API 這樣的方法調(diào)用需要轉(zhuǎn)換時更甚。
Java 原語類型的 autoboxing 和 auto-unboxing 產(chǎn)生更加精練并更加易于理解的代碼。1.5 版本讓所需要的轉(zhuǎn)換轉(zhuǎn)變成 Integer 并轉(zhuǎn)換回編譯器。
原來
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = (list.get(0)).intValue();
現(xiàn)在
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, 42);
int total = list.get(0);
增強的 for 循環(huán)
Collections API 經(jīng)常使用 Iterator 類。Iterator 類提供在 Collection 中順序?qū)Ш降臋C制。當(dāng)像下面一樣只是在 Collection 中遍歷時,新的增強的 for 循環(huán)可取代 iterator。編譯器生成必要的循環(huán)代碼,因為利用范型,所以不需要額外的類型轉(zhuǎn)換。
原來
ArrayList<Integer> list = new ArrayList<Integer>();
for (Iterator i = list.iterator(); i.hasNext();) {
Integer value=(Integer)i.next();
}
現(xiàn)在
ArrayList<Integer> list = new ArrayList<Integer>();
for (Integer i : list) { ... }
枚舉類型
當(dāng)使用 static final 型常量時,該類型提供枚舉的類型。如果您以前在自己的應(yīng)用程序中使用過標(biāo)識符 enum,那么在利用 javac -source 1.5 編譯時需要調(diào)整源代碼。
public enum StopLight { red, amber, green };
靜態(tài)導(dǎo)入
靜態(tài)導(dǎo)入特性實現(xiàn)為“import static”,允許您從一個類引用靜態(tài)常量,而不需要繼承這個類。每次我們添加一個組件時,不必使用 BorderLayout.CENTER,只要引用 CENTER 就可以了。
import static java.awt.BorderLayout.*;
getContentPane().add(new JPanel(), CENTER);
格式化的輸出
現(xiàn)在開發(fā)人員可以選擇使用 printf type 功能性來生成格式化的輸出。這將有助于遷移傳統(tǒng)的 C 應(yīng)用程序,作很少的更改或者不作更改就能保留相同的文本布局。
大多數(shù)公共 C printf 格式化程序是可用的,另外,一些 Java 類(比如 Date 和BigInteger)也具有格式化規(guī)則。更多信息請參見 java.util.Formatter 類。
System.out.printf("name count\n");
System.out.printf("%s %5d\n", user,total);
格式化的輸入
Scanner API 為從系統(tǒng)控制臺或任何數(shù)據(jù)流讀取數(shù)據(jù)提供基本的輸入功能性。下面的例子從標(biāo)準(zhǔn)輸入讀取一個 String 并期待下一個 int 值。
如果沒有數(shù)據(jù)可用,像 next 和 nextInt 這樣的 Scanner 方法將會阻塞。如果您需要處理更加復(fù)雜的輸入,那么從 java.util.Formatter 類還可以得到模式匹配算法。
Scanner s=Scanner.create(System.in);
String param= s.next();
int value=s.nextInt();
s.close();
Varargs
varargs(可變參數(shù))功能性允許多個參數(shù)傳遞作為方法的參數(shù)。它需要簡單的 ... 符號,該符號用于接收參數(shù)列表的方法,并且它還被用于實現(xiàn) printf 所需參數(shù)的靈活數(shù)量。
void argtest(Object ... args) {
for (int i=0;i <args.length; i++) {
}
}
argtest("test", "data");
并發(fā)實用程序
并發(fā)實用程序庫由 Doug Lea 定義在 JSR-166 中,是 J2SE 1.5 平臺中流行的并發(fā)軟件包的一個特殊版本。它提供強大的、高級別的線程構(gòu)造,包括 executors(這是一個線程任務(wù)框架)、線程安全隊列、Timers、鎖(包括原子鎖)和其他同步原語。
著名的旗語(semaphore)是這樣一個鎖。旗語與現(xiàn)在使用的 wait 的使用方式相同,用于限制對一塊代碼的訪問。旗語更加靈活,并且也允許許多并發(fā)的線程訪問,同時允許您在獲得一個鎖之前對它進(jìn)行測試。下面的例子使用剛好一個旗語,也叫做二進(jìn)制旗語。更多信息請參見 java.util.concurrent 軟件包。
final private Semaphore s= new Semaphore(1, true);
s.acquireUninterruptibly(); //for non-blocking version use s.acquire()
balance=balance+10; //protected value
s.release(); //return semaphore token
rmic —— rmi 編譯器
您不再需要使用 rmic —— rmi 編譯器工具——來生成最遠(yuǎn)程的接口存根。動態(tài)代理的引入意味著通常由存根提供的信息可以在運行時被發(fā)現(xiàn)。更多信息請參見 RMI 版本說明。
可擴(kuò)展性和性能
1.5 版本承諾在可擴(kuò)展性和性能方面的改進(jìn),新的重點在于啟動時間和內(nèi)存占用,使它更加易于以最大的速度部署應(yīng)用程序。
最重大的一個更新是引入了 Hotspot JVM 中的類數(shù)據(jù)共享。該技術(shù)不僅在多個正在運行的 JVM 之間共享只讀數(shù)據(jù),而且改進(jìn)了啟動時間,因為核心的 JVM 類都是預(yù)先打包的。
性能工效是 J2SE 1.5 中的一個新特性,這意味著如果您一直使用的是以前版本中專門的 JVM 運行時選項, 那么可能值得不用選項或者用很少的選項重新驗證您的性能。
監(jiān)控和可管理性
監(jiān)控和可管理性是 Java 平臺中的 RAS (Reliability, Availability, Serviceability,即可*性、可用性、可服務(wù)性) 的一個關(guān)鍵組件。
JVM Monitoring & Management API (JSR-174) 指定一組全面的可以從正在運行的 JVM 進(jìn)行監(jiān)控的 JVM internals。 該信息可通過 JMX (JSR-003) MBeans 訪問到,也可以使用 JMX 遠(yuǎn)程接口 (JSR-160) 和行業(yè)標(biāo)準(zhǔn) SNMP 工具而遠(yuǎn)程訪問得到。
最有用的一個特性是一個低內(nèi)存檢測程序。當(dāng)超過閥值時,JMX MBeans 可以通知已注冊的偵聽程序。更多信息請參見 javax.management 和 java.lang.management。
為了了解新的 API 是多么容易使用,下面報告了 Hotspot JVM 中內(nèi)存堆的詳細(xì)使用情況。
import java.lang.management.*;
import java.util.*;
import javax.management.*;
public class MemTest {
public static void main(String args[]) {
List pools =ManagementFactory.getMemoryPoolMBeans();
for(ListIterator i = pools.listIterator(); i.hasNext();) {
MemoryPoolMBean p = (MemoryPoolMBean) i.next();
System.out.println("Memory type="+p.getType()+" Memory usage="+p.getUsage());
}
}
}
新的 JVM profiling API (JSR-163)
該版本還包含一個更強大的本機 profiling API,叫做 JVMTI。該 API 已經(jīng)在 JSR 163 中指定了,并由對改善的 profiling 接口的需求所推動。但是,JVMTI 除了具有 profiling 功能之外,還想要涵蓋全范圍的本機內(nèi)部過程工具訪問,包括監(jiān)控工具、調(diào)試工具以及潛在的各種各樣的其他代碼分析工具。
該實現(xiàn)包含一個用于字節(jié)碼裝置(instrumentation)——Java 編程語言裝置服務(wù)(Java Programming Language Instrumentation Services,JPLIS)的機制。這使得分析工具只在需要的地方添加額外的配置信息(profiling)。該技術(shù)的優(yōu)點是,它允許更加集中的分析,并且限制了正在運行的 JVM 上的 profiling 工具的引用。該裝置甚至可以在運行時和類加載時動態(tài)地生成,并且可以作為類文件預(yù)先處理。
下面這個例子創(chuàng)建了一個裝置鉤(instrumentation hook),它可以從磁盤加載類文件的一個已修改的版本。要運行該測試,可利用 java -javaagent:myBCI BCITest 啟動 JRE。
//File myBCI.java
import java.lang.instrument.Instrumentation;
public class myBCI {
private static Instrumentation instCopy;
public static void premain(String options, Instrumentation inst) {
instCopy = inst;
}
public static Instrumentation getInstrumentation() {
return instCopy;
}
}
//File BCITest.java
import java.nio.*;
import java.io.*;
import java.nio.channels.*;
import java.lang.instrument.*;
public class BCITest {
public static void main (String[] args) {
try {
OriginalClass mc = new OriginalClass();
mc.message();
FileChannel fc=new FileInputStream(new File("modified"+File.separator+"OriginalClass.class")).getChannel();
ByteBuffer buf = fc.map(FileChannel.MapMode.READ_ONLY, 0, (int)fc.size());
byte[] classBuffer = new byte[buf.capacity()];
buf.get(classBuffer, 0, classBuffer.length);
myBCI.getInstrumentation().redefineClasses(new ClassDefinition[] {new ClassDefinition(mc.getClass(), classBuffer)});
mc.message();
}catch (Exception e){}
}
}
//OriginalClass.java
//Compile in current directory
//Copy source to modified directory,change message and recompile
public class OriginalClass {
public void message() {
System.out.println("OriginalClass");
}
}
改進(jìn)的診斷能力
如果沒有控制臺窗口可用,生成的 Stack 跟蹤就很笨拙。兩個新的 API —— getStackTrace 和 Thread.getAllStackTraces —— 以程序的方式提供該信息。
StackTraceElement e[]=Thread.currentThread().getStackTrace();
for (int i=0; i <e.length; i++) {
System.out.println(e);
}
System.out.println("\n"+Thread.getAllStackTraces());
Hotspot JVM 包含一個致命的錯誤處理程序(error hander),如果 JVM 異常中斷,它可以運行用戶提供的腳本。使用 Hotspot JVM 可服務(wù)性代理連接器,調(diào)試工具也可以連接到一個掛起的 JVM 或者核心文件。
-XX:OnError="command"
-XX:OnError="pmap %p"
-XX:OnError="gdb %p"
optional %p used as process id
桌面客戶端
Java 桌面客戶端保留有 Java 平臺的一個關(guān)鍵組件,并且這一點成了 J2SE 1.5 中許多改進(jìn)的焦點。
這個 Beta 版本包含啟動時間和內(nèi)存占用方面的一些早期改進(jìn)。該版本不僅更快,并且 Swing 工具集采用了一個暫新的叫做 Ocean 的主題。
通過建立 J2SE 1.4.2 中的更新,GTK 和 Windows XP 外觀方面有了更進(jìn)一步的改進(jìn)。
Windows XP
Click to Enlarge
Linux/Redhat
Click to Enlarge
具有最新 OpenGL 驅(qū)動程序并且選擇了圖形卡的 Linux 和 Solaris 用戶,可以使用下面的運行時屬性從 Java2D 獲得本機硬件加速:
java -Dsun.java2d.opengl=true -jar Java2D.
Linux 版本也具有快速的 X11 Toolkit,叫做 XAWT,默認(rèn)情況下是啟用的。如果您需要與 motif 版本進(jìn)行比較,可以使用下面的系統(tǒng)屬性:
java -Dawt.toolkit=sun.awt.motif.MToolkit -jar Notepad.jar
(X11 Toolkit 叫做 sun.awt.X11.XToolkit)
X11 Toolkit 也使用 XDnD 協(xié)議,所以您可以在 Java 和其他應(yīng)用(比如 StarOffice 或 Mozilla)之間拖放簡單的組件。
其他特性
核心 XML 支持
J2SE 1.5 引入了核心 XML 平臺的幾個修訂,包括 XML 1.1 和 Namespace、XML Schema、SAX 2.0.1、XSLT 和快速 XLSTC 編譯器,以及最后的 DOM 第 3 層支持。
除了支持核心 XML 之外,未來版本的 Java Web Services Developer Pack 將交付最新的 Web 服務(wù)標(biāo)準(zhǔn):JAX-RPC & SAAJ (WSDL/SOAP)、JAXB、XML Encryption and Digital Signature,以及用于注冊的 JAXR。
輔助字符支持
32 位的輔助字符支持作為傳輸?shù)?Unicode 4.0 支持的一部分,已經(jīng)慎重地添加到該平臺。輔助字符被編碼為一對特殊的 UTF16 值,以生成一個不同的字符或者碼點(codepoint)。一個代理對(surrogate pair)是一個高 UTF16 值和后面的一個低 UTF16 值的組合。這些高值和低值來自一個特殊范圍的 UTF16 值。
一般來說,當(dāng)使用 String 或者字符序列時,核心 API 庫將透明地為您處理新的輔助字符。但是因為 Java "char" 仍然保留為 16 位,所以非常少的一些使用 char 作為參數(shù)的方法,現(xiàn)在有了足夠的可以接受 int 值的方法,其中 int 值可以代表新的更大的值。特別是 Character 類,具有附加的方法來檢索當(dāng)前的字符和接下來的字符,以便檢索輔助的碼點值,如下所示:
String u="\uD840\uDC08";
System.out.println(u+"+ "+u.length());
System.out.println(Character.isHighSurrogate(u.charAt(0)));
System.out.println((int)u.charAt(1));
System.out.println((int)u.codePointAt(0));
更多信息請參見 Character 中的 Unicode 部分。
JDBC RowSets
JDBC 行集支持有兩個主要的更新。CachedRowSet 包含從數(shù)據(jù)庫檢索的行的內(nèi)存中的集合。但是它們也是不連接的,這意味著以后更新可以與數(shù)據(jù)庫重新同步。
另一個組件是 WebRowSet,它使用數(shù)據(jù)庫行通過 XML 來傳輸數(shù)據(jù)。
參考資料:
New Language Features for Ease of Development in the Java 2 Platform, Standard Edition 1.5: http://java.sun.com/features/2003/05/bloch_qa.html
Tiger Component JSRs
003 Java Management Extensions (JMX) Specification http://jcp.org/en/jsr/detail?id=3
013 Decimal Arithmetic Enhancement http://jcp.org/en/jsr/detail?id=13
014 Add Generic Types To The Java Programming Language http://jcp.org/en/jsr/detail?id=14
028 Java SASL Specification http://jcp.org/en/jsr/detail?id=28
114 JDBC Rowset Implementations http://jcp.org/en/jsr/detail?id=114
133 Java Memory Model and Thread Specification Revision http://jcp.org/en/jsr/detail?id=133
160 Java Management Extensions (JMX) Remote API 1.0 http://jcp.org/en/jsr/detail?id=160
163 Java Platform Profiling Architecture http://jcp.org/en/jsr/detail?id=163
166 Concurrency Utilities http://jcp.org/en/jsr/detail?id=166
174 Monitoring and Management Specification for the Java Virtual Machine http://jcp.org/en/jsr/detail?id=174
175 A Metadata Facility for the Java Programming Language http://jcp.org/en/jsr/detail?id=175
200 Network Transfer Format for Java Archives http://jcp.org/en/jsr/detail?id=200
201 Extending the Java Programming Language with Enumerations, Autoboxing, Enhanced for Loops and Static Import http://jcp.org/en/jsr/detail?id=201
204 Unicode Supplementary Character Support http://jcp.org/en/jsr/detail?id=204
206 Java API for XML Processing (JAXP) 1.3 http://jcp.org/en/jsr/detail?id=206