“造型”(Cast)的作用是“與一個模型匹配”。在適當的時候,Java會將一種數據類型自動轉換成另一種。例如,假設我們為浮點變量分配一個整數值,計算機會將int自動轉換成float。通過造型,我們可明確設置這種類型的轉換,或者在一般沒有可能進行的時候強迫它進行。
為進行一次造型,要將括號中希望的數據類型(包括所有修改符)置於其他任何值的左側。下面是一個例子:
void casts() {
int i = 200;
long l = (long)i;
long l2 = (long)200;
}
正如您看到的那樣,既可對一個數值進行造型處理,亦可對一個變量進行造型處理。但在這兒展示的兩種情況下,造型均是多余的,因為編譯器在必要的時候會自動進行int值到long值的轉換。當然,仍然可以設置一個造型,提醒自己留意,也使程序更清楚。在其他情況下,造型只有在代碼編譯時才顯出重要性。
在C和C++中,造型有時會讓人頭痛。在Java裡,造型則是一種比較安全的操作。但是,若進行一種名為“縮小轉換”(Narrowing Conversion)的操作(也就是說,腳本是能容納更多信息的數據類型,將其轉換成容量較小的類型),此時就可能面臨信息丟失的危險。此時,編譯器會強迫我們進行造型,就好象說:“這可能是一件危險的事情——如果您想讓我不顧一切地做,那麼對不起,請明確造型。”而對於“放大轉換”(Widening conversion),則不必進行明確造型,因為新類型肯定能容納原來類型的信息,不會造成任何信息的丟失。
Java允許我們將任何主類型“造型”為其他任何一種主類型,但布爾值(bollean)要除外,後者根本不允許進行任何造型處理。“類”不允許進行造型。為了將一種類轉換成另一種,必須采用特殊的方法(字串是一種特殊的情況,本書後面會講到將對象造型到一個類型“家族”裡;例如,“橡樹”可造型為“樹”;反之亦然。但對於其他外來類型,如“巖石”,則不能造型為“樹”)。
1. 字面值
最開始的時候,若在一個程序裡插入“字面值”(Literal),編譯器通常能准確知道要生成什麼樣的類型。但在有些時候,對於類型卻是暧昧不清的。若發生這種情況,必須對編譯器加以適當的“指導”。方法是用與字面值關聯的字符形式加入一些額外的信息。下面這段代碼向大家展示了這些字符。
//: Literals.java class Literals { char c = 0xffff; // max char hex value byte b = 0x7f; // max byte hex value short s = 0x7fff; // max short hex value int i1 = 0x2f; // Hexadecimal (lowercase) int i2 = 0X2F; // Hexadecimal (uppercase) int i3 = 0177; // Octal (leading zero) // Hex and Oct also work with long. long n1 = 200L; // long suffix long n2 = 200l; // long suffix long n3 = 200; //! long l6(200); // not allowed float f1 = 1; float f2 = 1F; // float suffix float f3 = 1f; // float suffix float f4 = 1e-45f; // 10 to the power float f5 = 1e+9f; // float suffix double d1 = 1d; // double suffix double d2 = 1D; // double suffix double d3 = 47e47d; // 10 to the power } ///:~
十六進制(Base 16)——它適用於所有整數數據類型——用一個前置的0x或0X指示。並在後面跟隨采用大寫或小寫形式的0-9以及a-f。若試圖將一個變量初始化成超出自身能力的一個值(無論這個值的數值形式如何),編譯器就會向我們報告一條出錯消息。注意在上述代碼中,最大的十六進制值只會在char,byte以及short身上出現。若超出這一限制,編譯器會將值自動變成一個int,並告訴我們需要對這一次賦值進行“縮小造型”。這樣一來,我們就可清楚獲知自己已超載了邊界。
八進制(Base 8)是用數字中的一個前置0以及0-7的數位指示的。在C,C++或者Java中,對二進制數字沒有相應的“字面”表示方法。
字面值後的尾隨字符標志著它的類型。若為大寫或小寫的L,代表long;大寫或小寫的F,代表float;大寫或小寫的D,則代表double。
指數總是采用一種我們認為很不直觀的記號方法:1.39e-47f。在科學與工程學領域,“e”代表自然對數的基數,約等於2.718(Java一種更精確的double值采用Math.E的形式)。它在象“1.39×e的-47次方”這樣的指數表達式中使用,意味著“1.39×2.718的-47次方”。然而,自FORTRAN語言發明後,人們自然而然地覺得e代表“10多少次冪”。這種做法顯得頗為古怪,因為FORTRAN最初面向的是科學與工程設計領域。理所當然,它的設計者應對這樣的混淆概念持謹慎態度(注釋①)。但不管怎樣,這種特別的表達方法在C,C++以及現在的Java中頑固地保留下來了。所以倘若您習慣將e作為自然對數的基數使用,那麼在Java中看到象“1.39e-47f”這樣的表達式時,請轉換您的思維,從程序設計的角度思考它;它真正的含義是“1.39×10的-47次方”。
①:John Kirkham這樣寫道:“我最早於1962年在一部IBM 1620機器上使用FORTRAN II。那時——包括60年代以及70年代的早期,FORTRAN一直都是使用大寫字母。之所以會出現這一情況,可能是由於早期的輸入設備大多是老式電傳打字機,使用5位Baudot碼,那種碼並不具備小寫能力。乘冪表達式中的‘E’也肯定是大寫的,所以不會與自然對數的基數‘e’發生沖突,後者必然是小寫的。‘E’這個字母的含義其實很簡單,就是‘Exponential’的意思,即‘指數’或‘冪數’,代表計算系統的基數——一般都是10。當時,八進制也在程序員中廣泛使用。盡管我自己未看到它的使用,但假若我在乘冪表達式中看到一個八進制數字,就會把它認作Base 8。我記得第一次看到用小寫‘e’表示指數是在70年代末期。我當時也覺得它極易產生混淆。所以說,這個問題完全是自己‘潛入’FORTRAN裡去的,並非一開始就有。如果你真的想使用自然對數的基數,實際有現成的函數可供利用,但它們都是大寫的。”
注意如果編譯器能夠正確地識別類型,就不必使用尾隨字符。對於下述語句:
long n3 = 200;
它並不存在含混不清的地方,所以200後面的一個L大可省去。然而,對於下述語句:
float f4 = 1e-47f; //10的冪數
編譯器通常會將指數作為雙精度數(double)處理,所以假如沒有這個尾隨的f,就會收到一條出錯提示,告訴我們須用一個“造型”將double轉換成float。
2. 轉型
大家會發現假若對主數據類型執行任何算術或按位運算,只要它們“比int小”(即char,byte或者short),那麼在正式執行運算之前,那些值會自動轉換成int。這樣一來,最終生成的值就是int類型。所以只要把一個值賦回較小的類型,就必須使用“造型”。此外,由於是將值賦回給較小的類型,所以可能出現信息丟失的情況)。通常,表達式中最大的數據類型是決定了表達式最終結果大小的那個類型。若將一個float值與一個double值相乘,結果就是double;如將一個int和一個long值相加,則結果為long。