Java 2 Platform, Standard Edition (J2SE) 1.5 版("Tiger")是 Java 平臺(tái)和語(yǔ)言的下一個(gè)主要修訂版。它包含了 15 個(gè)組件 JSR 以及由 Java 社團(tuán)(Java Community Process,JCP)開發(fā)的其他將近100個(gè)重大更新。
對(duì)于這個(gè)版本中如此多令人興奮的變化,您也許很想知道從何處入手。與以前的版本一樣,版本說明手冊(cè) 中列出了所有的變化。本文來自于 J2SE 團(tuán)隊(duì),帶您遍歷一些主要的變化,以便您在閱讀 API 文檔 之前了解 J2SE 1.5 提供的要點(diǎn)。
J2SE 1.5 版關(guān)注以下關(guān)鍵主題:
還有少數(shù)的特性雖然重要但是不能歸類于這些主題,所以在最后面列出來:
易于開發(fā)性
您也許已經(jīng)見過這樣的報(bào)告,即一些新的 Java 語(yǔ)言變化包含易于開發(fā)性主題。這些變化包括泛型、元數(shù)據(jù)、autoboxing、增強(qiáng)的 for 循環(huán)、枚舉類型、靜態(tài)導(dǎo)入、C 風(fēng)格的格式化 I/O、可變參數(shù)、并發(fā)實(shí)用程序以及更簡(jiǎn)單的 RMI 接口生成。
JSR 201 包括如下四個(gè)語(yǔ)言變化:增強(qiáng)的 for 循環(huán)、枚舉類型、靜態(tài)導(dǎo)入和 autoboxing;JSR 175 指定了新的元數(shù)據(jù)功能,而 JSR 14 則詳細(xì)說明了泛型。
javac 編譯器執(zhí)行的默認(rèn)語(yǔ)言規(guī)范是版本 1.4。這意味著要利用以下語(yǔ)言變化的任何好處,需要向 javac 命令傳遞參數(shù) -source 1.5。
元數(shù)據(jù)
J2SE 1.5 中的元數(shù)據(jù)特性提供這樣的能力,即向 Java 類、接口、方法和字段關(guān)聯(lián)附加的數(shù)據(jù)。這些附加的數(shù)據(jù)或者注釋,可以被 javac 編譯器或其他工具讀取,并且根據(jù)配置不同,可以被保存在類文件中,也可以在運(yùn)行時(shí)使用 Java 反射 API 被發(fā)現(xiàn)。
向 Java 平臺(tái)增加元數(shù)據(jù)的一個(gè)主要原因是,使得開發(fā)工具和運(yùn)行工具有一個(gè)通用的基礎(chǔ)結(jié)構(gòu),以減少開發(fā)和部署所需的成本。工具可以使用元數(shù)據(jù)信息生成附加的源代碼,或者在調(diào)試時(shí)提供附加信息。
下面的例子用元數(shù)據(jù)工具創(chuàng)建了一個(gè)調(diào)試元數(shù)據(jù)注釋,這些元數(shù)據(jù)注釋然后又簡(jiǎn)單地在運(yùn)行時(shí)顯示出來。可以想像,大部分的元數(shù)據(jù)標(biāo)簽形成一個(gè)標(biāo)準(zhǔn),即一個(gè)良好規(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[i]+" ");
}
} catch(NoSuchMethodException e) {
System.out.println(e);
}
}
}
|
利用一個(gè)元數(shù)據(jù)處理工具,許多重復(fù)的代碼編寫步驟可以減少成一個(gè)簡(jiǎn)練的元數(shù)據(jù)標(biāo)簽。例如,訪問某個(gè) JAX-RPC 服務(wù)實(shí)現(xiàn)時(shí)所需的遠(yuǎn)程接口可以實(shí)現(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 提供可以被多個(gè) Java 類型使用的公共功能性,比如 LinkedLists、
ArrayLists
和 HashMaps
。下一個(gè)例子使用 1.4.2 庫(kù)和默認(rèn)的 javac 編譯模式。
ArrayList list = new ArrayList();
list.add(0, new Integer(42));
int total = ((Integer)list.get(0)).intValue();
|
最后一行中的 Integer
轉(zhuǎn)換是泛型所要防止的強(qiáng)制類型轉(zhuǎn)換問題的一個(gè)例子。這個(gè)問題在于,1.4.2 Collections API 使用 Object
類來存儲(chǔ) Collection
對(duì)象,這就意味著在編譯的時(shí)候不能找出類型匹配。問題的第一個(gè)標(biāo)志信息是在運(yùn)行時(shí)拋出的 ClassCastException
。
帶有范型化 Collections 庫(kù)的同一個(gè)例子可編寫為:
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(0, new Integer(42));
int total = list.get(0).intValue();
|
范型化 API 的用戶必須使用 <> 符號(hào)簡(jiǎn)單地聲明在編譯類型中使用的類型。不需要任何類型轉(zhuǎn)換,在本例中試圖向一個(gè) Integer
類型的集合中添加 String
對(duì)象將會(huì)在編譯時(shí)被捕獲。
因此,范型允許 API 設(shè)計(jì)者提供這樣的公共功能性:可以與多種數(shù)據(jù)類型一起使用,也可以在編譯時(shí)出于類型安全對(duì)它進(jìn)行檢查。
設(shè)計(jì)自己的 Generic API 比起只是使用它們來說要稍微復(fù)雜一些。請(qǐng)從查看 java.util.Collection
源代碼和 API 指南開始。
原語(yǔ)類型的 Autoboxing 和 Auto-unboxing
像 int、boolean 以及它們的基于對(duì)象的對(duì)應(yīng)物(比如 Integer 和 Boolean)這樣的原語(yǔ)類型之間的轉(zhuǎn)換需要大量不必要的額外編碼, 尤其是當(dāng)只是像 Collections API 這樣的方法調(diào)用需要轉(zhuǎn)換時(shí)更甚。
Java 原語(yǔ)類型的 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);
|
增強(qiáng)的 for 循環(huán)
Collections API 經(jīng)常使用 Iterator
類。Iterator
類提供在 Collection 中順序?qū)Ш降臋C(jī)制。當(dāng)像下面一樣只是在 Collection 中遍歷時(shí),新的增強(qiáng)的 for 循環(huán)可取代 iterator。編譯器生成必要的循環(huán)代碼,因?yà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 型常量時(shí),該類型提供枚舉的類型。如果您以前在自己的應(yīng)用程序中使用過標(biāo)識(shí)符 enum,那么在利用 javac
-source 1.5 編譯時(shí)需要調(diào)整源代碼。
public enum StopLight { red, amber, green };
|
靜態(tài)導(dǎo)入
靜態(tài)導(dǎo)入特性實(shí)現(xiàn)為“import static”,允許您從一個(gè)類引用靜態(tài)常量,而不需要繼承這個(gè)類。每次我們添加一個(gè)組件時(shí),不必使用 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ī)則。更多信息請(qǐng)參見 java.util.Formatter
類。
System.out.printf("name count\n");
System.out.printf("%s %5d\n", user,total);
|
格式化的輸入
Scanner API 為從系統(tǒng)控制臺(tái)或任何數(shù)據(jù)流讀取數(shù)據(jù)提供基本的輸入功能性。下面的例子從標(biāo)準(zhǔn)輸入讀取一個(gè) String 并期待下一個(gè) int 值。
如果沒有數(shù)據(jù)可用,像 next
和 nextInt
這樣的 Scanner 方法將會(huì)阻塞。如果您需要處理更加復(fù)雜的輸入,那么從 java.util.Formatter
類還可以得到模式匹配算法。
Scanner s=Scanner.create(System.in);
String param= s.next();
int value=s.nextInt();
s.close();
|
Varargs
varargs(可變參數(shù))功能性允許多個(gè)參數(shù)傳遞作為方法的參數(shù)。它需要簡(jiǎn)單的 ... 符號(hào),該符號(hào)用于接收參數(shù)列表的方法,并且它還被用于實(shí)現(xiàn) printf 所需參數(shù)的靈活數(shù)量。
void argtest(Object ... args) {
for (int i=0;i <args.length; i++) {
}
}
argtest("test", "data");
|
并發(fā)實(shí)用程序
并發(fā)實(shí)用程序庫(kù)由 Doug Lea 定義在 JSR-166 中,是 J2SE 1.5 平臺(tái)中流行的并發(fā)軟件包的一個(gè)特殊版本。它提供強(qiáng)大的、高級(jí)別的線程構(gòu)造,包括 executors(這是一個(gè)線程任務(wù)框架)、線程安全隊(duì)列、Timers、鎖(包括原子鎖)和其他同步原語(yǔ)。
著名的旗語(yǔ)(semaphore)是這樣一個(gè)鎖。旗語(yǔ)與現(xiàn)在使用的 wait
的使用方式相同,用于限制對(duì)一塊代碼的訪問。旗語(yǔ)更加靈活,并且也允許許多并發(fā)的線程訪問,同時(shí)允許您在獲得一個(gè)鎖之前對(duì)它進(jìn)行測(cè)試。下面的例子使用剛好一個(gè)旗語(yǔ),也叫做二進(jìn)制旗語(yǔ)。更多信息請(qǐng)參見 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)程的接口存根。動(dòng)態(tài)代理的引入意味著通常由存根提供的信息可以在運(yùn)行時(shí)被發(fā)現(xiàn)。更多信息請(qǐng)參見 RMI 版本說明。
可擴(kuò)展性和性能
1.5 版本承諾在可擴(kuò)展性和性能方面的改進(jìn),新的重點(diǎn)在于啟動(dòng)時(shí)間和內(nèi)存占用,使它更加易于以最大的速度部署應(yīng)用程序。
最重大的一個(gè)更新是引入了 Hotspot JVM 中的類數(shù)據(jù)共享。該技術(shù)不僅在多個(gè)正在運(yùn)行的 JVM 之間共享只讀數(shù)據(jù),而且改進(jìn)了啟動(dòng)時(shí)間,因?yàn)楹诵牡?JVM 類都是預(yù)先打包的。
性能工效是 J2SE 1.5 中的一個(gè)新特性,這意味著如果您一直使用的是以前版本中專門的 JVM 運(yùn)行時(shí)選項(xiàng), 那么可能值得不用選項(xiàng)或者用很少的選項(xiàng)重新驗(yàn)證您的性能。
監(jiān)控和可管理性
監(jiān)控和可管理性是 Java 平臺(tái)中的 RAS (Reliability, Availability, Serviceability,即可靠性、可用性、可服務(wù)性) 的一個(gè)關(guān)鍵組件。
JVM Monitoring & Management API (JSR-174) 指定一組全面的可以從正在運(yùn)行的 JVM 進(jìn)行監(jiān)控的 JVM internals。 該信息可通過 JMX (JSR-003) MBeans 訪問到,也可以使用 JMX 遠(yuǎn)程接口 (JSR-160) 和行業(yè)標(biāo)準(zhǔn) SNMP 工具而遠(yuǎn)程訪問得到。
最有用的一個(gè)特性是一個(gè)低內(nèi)存檢測(cè)程序。當(dāng)超過閥值時(shí),JMX MBeans 可以通知已注冊(cè)的偵聽程序。更多信息請(qǐng)參見 javax.management 和 java.lang.management。
為了了解新的 API 是多么容易使用,下面報(bào)告了 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)
該版本還包含一個(gè)更強(qiáng)大的本機(jī) profiling API,叫做 JVMTI。該 API 已經(jīng)在 JSR 163 中指定了,并由對(duì)改善的 profiling 接口的需求所推動(dòng)。但是,JVMTI 除了具有 profiling 功能之外,還想要涵蓋全范圍的本機(jī)內(nèi)部過程工具訪問,包括監(jiān)控工具、調(diào)試工具以及潛在的各種各樣的其他代碼分析工具。
該實(shí)現(xiàn)包含一個(gè)用于字節(jié)碼裝置(instrumentation)——Java 編程語(yǔ)言裝置服務(wù)(Java Programming Language Instrumentation Services,JPLIS)的機(jī)制。這使得分析工具只在需要的地方添加額外的配置信息(profiling)。該技術(shù)的優(yōu)點(diǎn)是,它允許更加集中的分析,并且限制了正在運(yùn)行的 JVM 上的 profiling 工具的引用。該裝置甚至可以在運(yùn)行時(shí)和類加載時(shí)動(dòng)態(tài)地生成,并且可以作為類文件預(yù)先處理。
下面這個(gè)例子創(chuàng)建了一個(gè)裝置鉤(instrumentation hook),它可以從磁盤加載類文件的一個(gè)已修改的版本。要運(yùn)行該測(cè)試,可利用 java -javaagent:myBCI BCITest
啟動(dòng) 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)的診斷能力
如果沒有控制臺(tái)窗口可用,生成的 Stack 跟蹤就很笨拙。兩個(gè)新的 API —— getStackTrace
和 Thread.getAllStackTraces
—— 以程序的方式提供該信息。
StackTraceElement e[]=Thread.currentThread().getStackTrace();
for (int i=0; i <e.length; i++) {
System.out.println(e[i]);
}
System.out.println("\n"+Thread.getAllStackTraces());
|
Hotspot JVM 包含一個(gè)致命的錯(cuò)誤處理程序(error hander),如果 JVM 異常中斷,它可以運(yùn)行用戶提供的腳本。使用 Hotspot JVM 可服務(wù)性代理連接器,調(diào)試工具也可以連接到一個(gè)掛起的 JVM 或者核心文件。
-XX:OnError="command"
-XX:OnError="pmap %p"
-XX:OnError="gdb %p"
optional %p used as process id
|
桌面客戶端
Java 桌面客戶端保留有 Java 平臺(tái)的一個(gè)關(guān)鍵組件,并且這一點(diǎn)成了 J2SE 1.5 中許多改進(jìn)的焦點(diǎn)。
這個(gè) Beta 版本包含啟動(dòng)時(shí)間和內(nèi)存占用方面的一些早期改進(jìn)。該版本不僅更快,并且 Swing 工具集采用了一個(gè)暫新的叫做 Ocean 的主題。
通過建立 J2SE 1.4.2 中的更新,GTK 和 Windows XP 外觀方面有了更進(jìn)一步的改進(jìn)。
?
具有最新 OpenGL 驅(qū)動(dòng)程序并且選擇了圖形卡的 Linux 和 Solaris 用戶,可以使用下面的運(yùn)行時(shí)屬性從 Java2D 獲得本機(jī)硬件加速:
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)之間拖放簡(jiǎn)單的組件。
其他特性
核心 XML 支持
J2SE 1.5 引入了核心 XML 平臺(tái)的幾個(gè)修訂,包括 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,以及用于注冊(cè)的 JAXR。
輔助字符支持
32 位的輔助字符支持作為傳輸?shù)?Unicode 4.0 支持的一部分,已經(jīng)慎重地添加到該平臺(tái)。輔助字符被編碼為一對(duì)特殊的 UTF16 值,以生成一個(gè)不同的字符或者碼點(diǎn)(codepoint)。一個(gè)代理對(duì)(surrogate pair)是一個(gè)高 UTF16 值和后面的一個(gè)低 UTF16 值的組合。這些高值和低值來自一個(gè)特殊范圍的 UTF16 值。
一般來說,當(dāng)使用 String 或者字符序列時(shí),核心 API 庫(kù)將透明地為您處理新的輔助字符。但是因?yàn)?Java "char" 仍然保留為 16 位,所以非常少的一些使用 char 作為參數(shù)的方法,現(xiàn)在有了足夠的可以接受 int 值的方法,其中 int 值可以代表新的更大的值。特別是 Character 類,具有附加的方法來檢索當(dāng)前的字符和接下來的字符,以便檢索輔助的碼點(diǎn)值,如下所示:
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));
|
更多信息請(qǐng)參見 Character 中的 Unicode 部分。
JDBC RowSets
JDBC 行集支持有兩個(gè)主要的更新。CachedRowSet
包含從數(shù)據(jù)庫(kù)檢索的行的內(nèi)存中的集合。但是它們也是不連接的,這意味著以后更新可以與數(shù)據(jù)庫(kù)重新同步。
另一個(gè)組件是 WebRowSet
,它使用數(shù)據(jù)庫(kù)行通過 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