您也許已經見過這樣的報告,即一些新的 Java 語言變化包含易于開發性主題。這些變化包括泛型、元數據、autoboxing、增強的 for 循環、枚舉類型、靜態導入、C 風格的格式化 I/O、可變參數、并發實用程序以及更簡單的 RMI 接口生成。
JSR 201 包括如下四個語言變化:增強的 for 循環、枚舉類型、靜態導入和 autoboxing;JSR 175 指定了新的元數據功能,而 JSR 14 則詳細說明了泛型。
javac 編譯器執行的默認語言規范是版本 1.4。這意味著要利用以下語言變化的任何好處,需要向 javac 命令傳遞參數 -source 1.5。
元數據
J2SE 1.5 中的元數據特性提供這樣的能力,即向 Java 類、接口、方法和字段關聯附加的數據。這些附加的數據或者注釋,可以被 javac 編譯器或其他工具讀取,并且根據配置不同,可以被保存在類文件中,也可以在運行時使用 Java 反射 API 被發現。
向 Java 平臺增加元數據的一個主要原因是,使得開發工具和運行工具有一個通用的基礎結構,以減少開發和部署所需的成本。工具可以使用元數據信息生成附加的源代碼,或者在調試時提供附加信息。
下面的例子用元數據工具創建了一個調試元數據注釋,這些元數據注釋然后又簡單地在運行時顯示出來。可以想像,大部分的元數據標簽形成一個標準,即一個良好規范的集合。
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);
}
}
}
利用一個元數據處理工具,許多重復的代碼編寫步驟可以減少成一個簡練的元數據標簽。例如,訪問某個 JAX-RPC 服務實現時所需的遠程接口可以實現為:
原來(J2SE 1.5 以前版本):
public interface PingIF extends Remote {
public void ping() throws RemoteException;
}
public class Ping implements PingIF {
public void ping() {
}
}
現在:
public class Ping {
public @remote void ping() {
}
}
范型
范型一直是 Java 社團所廣泛期待的,現在已經是 J2SE 1.5 的一部分了。最先見到使用泛型的地方是在 Collections API 中。Collections API 提供可以被多個 Java 類型使用的公共功能性,比如 LinkedLists、ArrayLists 和 HashMaps。下一個例子使用 1.4.2 庫和默認的 javac 編譯模式。
ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = ((Integer)list.get(0)).intValue();
最后一行中的 Integer 轉換是泛型所要防止的強制類型轉換問題的一個例子。這個問題在于,1.4.2 Collections API 使用 Object 類來存儲 Collection 對象,這就意味著在編譯的時候不能找出類型匹配。問題的第一個標志信息是在運行時拋出的 ClassCastException。
帶有范型化 Collections 庫的同一個例子可編寫為:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = list.get(0).intValue();
范型化 API 的用戶必須使用 <> 符號簡單地聲明在編譯類型中使用的類型。不需要任何類型轉換,在本例中試圖向一個 Integer 類型的集合中添加 String 對象將會在編譯時被捕獲。
因此,范型允許 API 設計者提供這樣的公共功能性:可以與多種數據類型一起使用,也可以在編譯時出于類型安全對它進行檢查。
設計自己的 Generic API 比起只是使用它們來說要稍微復雜一些。請從查看 java.util.Collection 源代碼和 API 指南開始。
原語類型的 Autoboxing 和 Auto-unboxing
像 int、boolean 以及它們的基于對象的對應物(比如 Integer 和 Boolean)這樣的原語類型之間的轉換需要大量不必要的額外編碼, 尤其是當只是像 Collections API 這樣的方法調用需要轉換時更甚。
Java 原語類型的 autoboxing 和 auto-unboxing 產生更加精練并更加易于理解的代碼。1.5 版本讓所需要的轉換轉變成 Integer 并轉換回編譯器。
原來
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = (list.get(0)).intValue();
現在
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, 42);
int total = list.get(0);
增強的 for 循環
Collections API 經常使用 Iterator 類。Iterator 類提供在 Collection 中順序導航的機制。當像下面一樣只是在 Collection 中遍歷時,新的增強的 for 循環可取代 iterator。編譯器生成必要的循環代碼,因為利用范型,所以不需要額外的類型轉換。
原來
ArrayList<Integer> list = new ArrayList<Integer>();
for (Iterator i = list.iterator(); i.hasNext();) {
Integer value=(Integer)i.next();
}
現在
ArrayList<Integer> list = new ArrayList<Integer>();
for (Integer i : list) { ... }
枚舉類型
當使用 static final 型常量時,該類型提供枚舉的類型。如果您以前在自己的應用程序中使用過標識符 enum,那么在利用 javac -source 1.5 編譯時需要調整源代碼。
public enum StopLight { red, amber, green };
靜態導入
靜態導入特性實現為“import static”,允許您從一個類引用靜態常量,而不需要繼承這個類。每次我們添加一個組件時,不必使用 BorderLayout.CENTER,只要引用 CENTER 就可以了。
import static java.awt.BorderLayout.*;
getContentPane().add(new JPanel(), CENTER);
格式化的輸出
現在開發人員可以選擇使用 printf type 功能性來生成格式化的輸出。這將有助于遷移傳統的 C 應用程序,作很少的更改或者不作更改就能保留相同的文本布局。
大多數公共 C printf 格式化程序是可用的,另外,一些 Java 類(比如 Date 和BigInteger)也具有格式化規則。更多信息請參見 java.util.Formatter 類。
System.out.printf("name count\n");
System.out.printf("%s %5d\n", user,total);
格式化的輸入
Scanner API 為從系統控制臺或任何數據流讀取數據提供基本的輸入功能性。下面的例子從標準輸入讀取一個 String 并期待下一個 int 值。
如果沒有數據可用,像 next 和 nextInt 這樣的 Scanner 方法將會阻塞。如果您需要處理更加復雜的輸入,那么從 java.util.Formatter 類還可以得到模式匹配算法。
Scanner s=Scanner.create(System.in);
String param= s.next();
int value=s.nextInt();
s.close();
Varargs
varargs(可變參數)功能性允許多個參數傳遞作為方法的參數。它需要簡單的 ... 符號,該符號用于接收參數列表的方法,并且它還被用于實現 printf 所需參數的靈活數量。
void argtest(Object ... args) {
for (int i=0;i <args.length; i++) {
}
}
argtest("test", "data");
并發實用程序
并發實用程序庫由 Doug Lea 定義在 JSR-166 中,是 J2SE 1.5 平臺中流行的并發軟件包的一個特殊版本。它提供強大的、高級別的線程構造,包括 executors(這是一個線程任務框架)、線程安全隊列、Timers、鎖(包括原子鎖)和其他同步原語。
著名的旗語(semaphore)是這樣一個鎖。旗語與現在使用的 wait 的使用方式相同,用于限制對一塊代碼的訪問。旗語更加靈活,并且也允許許多并發的線程訪問,同時允許您在獲得一個鎖之前對它進行測試。下面的例子使用剛好一個旗語,也叫做二進制旗語。更多信息請參見 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 編譯器工具——來生成最遠程的接口存根。動態代理的引入意味著通常由存根提供的信息可以在運行時被發現。更多信息請參見 RMI 版本說明。
可擴展性和性能
1.5 版本承諾在可擴展性和性能方面的改進,新的重點在于啟動時間和內存占用,使它更加易于以最大的速度部署應用程序。
最重大的一個更新是引入了 Hotspot JVM 中的類數據共享。該技術不僅在多個正在運行的 JVM 之間共享只讀數據,而且改進了啟動時間,因為核心的 JVM 類都是預先打包的。
性能工效是 J2SE 1.5 中的一個新特性,這意味著如果您一直使用的是以前版本中專門的 JVM 運行時選項, 那么可能值得不用選項或者用很少的選項重新驗證您的性能。
監控和可管理性
監控和可管理性是 Java 平臺中的 RAS (Reliability, Availability, Serviceability,即可*性、可用性、可服務性) 的一個關鍵組件。
JVM Monitoring & Management API (JSR-174) 指定一組全面的可以從正在運行的 JVM 進行監控的 JVM internals。 該信息可通過 JMX (JSR-003) MBeans 訪問到,也可以使用 JMX 遠程接口 (JSR-160) 和行業標準 SNMP 工具而遠程訪問得到。
最有用的一個特性是一個低內存檢測程序。當超過閥值時,JMX MBeans 可以通知已注冊的偵聽程序。更多信息請參見 javax.management 和 java.lang.management。
為了了解新的 API 是多么容易使用,下面報告了 Hotspot JVM 中內存堆的詳細使用情況。
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 已經在 JSR 163 中指定了,并由對改善的 profiling 接口的需求所推動。但是,JVMTI 除了具有 profiling 功能之外,還想要涵蓋全范圍的本機內部過程工具訪問,包括監控工具、調試工具以及潛在的各種各樣的其他代碼分析工具。
該實現包含一個用于字節碼裝置(instrumentation)——Java 編程語言裝置服務(Java Programming Language Instrumentation Services,JPLIS)的機制。這使得分析工具只在需要的地方添加額外的配置信息(profiling)。該技術的優點是,它允許更加集中的分析,并且限制了正在運行的 JVM 上的 profiling 工具的引用。該裝置甚至可以在運行時和類加載時動態地生成,并且可以作為類文件預先處理。
下面這個例子創建了一個裝置鉤(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");
}
}
改進的診斷能力
如果沒有控制臺窗口可用,生成的 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 可服務性代理連接器,調試工具也可以連接到一個掛起的 JVM 或者核心文件。
-XX:OnError="command"
-XX:OnError="pmap %p"
-XX:OnError="gdb %p"
optional %p used as process id
桌面客戶端
Java 桌面客戶端保留有 Java 平臺的一個關鍵組件,并且這一點成了 J2SE 1.5 中許多改進的焦點。
這個 Beta 版本包含啟動時間和內存占用方面的一些早期改進。該版本不僅更快,并且 Swing 工具集采用了一個暫新的叫做 Ocean 的主題。
通過建立 J2SE 1.4.2 中的更新,GTK 和 Windows XP 外觀方面有了更進一步的改進。
Windows XP
Click to Enlarge
Linux/Redhat
Click to Enlarge
具有最新 OpenGL 驅動程序并且選擇了圖形卡的 Linux 和 Solaris 用戶,可以使用下面的運行時屬性從 Java2D 獲得本機硬件加速:
java -Dsun.java2d.opengl=true -jar Java2D.
Linux 版本也具有快速的 X11 Toolkit,叫做 XAWT,默認情況下是啟用的。如果您需要與 motif 版本進行比較,可以使用下面的系統屬性:
java -Dawt.toolkit=sun.awt.motif.MToolkit -jar Notepad.jar
(X11 Toolkit 叫做 sun.awt.X11.XToolkit)
X11 Toolkit 也使用 XDnD 協議,所以您可以在 Java 和其他應用(比如 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 服務標準:JAX-RPC & SAAJ (WSDL/SOAP)、JAXB、XML Encryption and Digital Signature,以及用于注冊的 JAXR。
輔助字符支持
32 位的輔助字符支持作為傳輸到 Unicode 4.0 支持的一部分,已經慎重地添加到該平臺。輔助字符被編碼為一對特殊的 UTF16 值,以生成一個不同的字符或者碼點(codepoint)。一個代理對(surrogate pair)是一個高 UTF16 值和后面的一個低 UTF16 值的組合。這些高值和低值來自一個特殊范圍的 UTF16 值。
一般來說,當使用 String 或者字符序列時,核心 API 庫將透明地為您處理新的輔助字符。但是因為 Java "char" 仍然保留為 16 位,所以非常少的一些使用 char 作為參數的方法,現在有了足夠的可以接受 int 值的方法,其中 int 值可以代表新的更大的值。特別是 Character 類,具有附加的方法來檢索當前的字符和接下來的字符,以便檢索輔助的碼點值,如下所示:
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 包含從數據庫檢索的行的內存中的集合。但是它們也是不連接的,這意味著以后更新可以與數據庫重新同步。
另一個組件是 WebRowSet,它使用數據庫行通過 XML 來傳輸數據。
參考資料:
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