2011-11-03 65 views
4

我只想知道Java中的一件簡單的事情。讓我們考慮以下Java代碼段。Java中是否存在運算符重載?

int x=10; 
String temp="x = "+x; 
System.out.println(temp); 

在Java中是完全有效的,併產生輸出x = 10作爲字符串。


雖然,變量x是類型INT的,它被自動轉換爲字符串類型(一包裝型)。 Java如何做到這一點? Java是否像Java和C++一樣存在於Java中的操作符重載,儘管它已從Java中移除。 這裏使用了哪個特定的概念將x轉換爲字符串。我唯一想知道


而且,還有一個問題,在Java中的布爾數據類型(不是布爾,包裝類),不能轉換爲任何其他類型(按照我知道)。爲什麼如此,在某些特定情況下,將其轉換爲字符串或其他類型可能很有用。

+0

請只問一個問題。 – Tim

+2

要回答你的身邊的問題,唯一的事情是真正有用的一個布爾值,另一種形式將被輸出到用戶或其他一些人類可讀的形式,並將其轉換爲「真」或「假」追加到時字符串或StringBuilder。除此之外,它應該由開發人員單獨處理,而不是施放。 – corsiKa

+0

儘管JDBC驅動程序將布爾轉換爲PL/SQL數字0和1是很好的,所以我不必編寫一堆糟糕的幫助程序。 ;-) –

回答

9

編譯器轉換這句話(「X =」 + X)爲內部一個StringBuilder並使用.append(int)以將整數「添加」到字符串中。

爲了超越實際的「Java如何做到這一點」,我會聽取Stephen的建議並給出理論。從概念上講,連接中的每個值首先轉換爲一個字符串,然後連接。空值被連接爲單詞「null」。

Java Language Specification

15.18.1.1字符串轉換

任何類型的可轉換由字符串轉換爲類型字符串。給它作爲參數傳遞給適當的類實例創建 表達的值由 原始類型T的 X首先被轉換爲一個基準值,如果:

如果T是布爾值,然後使用新的布爾值(x)的。如果T是char,則使用新的 Character(x)。如果T是byte,short或int,則使用新的Integer(x)。如果 T很長,則使用新的Long(x)。如果T爲浮點數,則使用新的Float(x)。 如果T是雙倍,則使用新的Double(x)。然後通過字符串轉換將此參考值轉換爲字符串類型 。現在只需要考慮參考 的值。如果引用爲空,則將其轉換爲字符串「null」(四個ASCII字符n,u,l,l)的 。 否則,執行轉換就好像通過調用引用對象的無參數的 toString方法;但如果調用toString方法的結果爲 爲空,則將使用字符串「null」 代替。

toString方法由原始類Object定義;許多 類重載它,特別是布爾型,字符型,整型,長整型,浮點型, Double和String。字符串連接

一種實現的

15.18.1.2優化可以選擇在一個步驟中執行轉換和級聯 以避免創建然後丟棄一箇中間 字符串對象。爲了提高重複字符串連接的性能,Java編譯器可以使用StringBuffer類或類似的技術來減少通過評估表達式創建的中間String對象的數量 。對於基本類型,實現還可以通過直接從基元類型轉換爲字符串來優化對象的創建包裝對象 。

優化後的版本實際上並不會實際進行完整包裝的字符串轉換。

這是由編譯器所使用的,儘管沒有一個原始的,在這裏可以看到,編譯器改變事物到在後臺一個StringBuilder的轉化的優化版本很好地說明:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/

這java代碼:

public static void main(String[] args) { 
    String cip = "cip"; 
    String ciop = "ciop"; 
    String plus = cip + ciop; 
    String build = new StringBuilder(cip).append(ciop).toString(); 
} 

生成此 - 看到兩個級聯樣式如何導致同樣的BYTEC ODE:

L0 
    LINENUMBER 23 L0 
    LDC "cip" 
    ASTORE 1 
    L1 
    LINENUMBER 24 L1 
    LDC "ciop" 
    ASTORE 2 
// cip + ciop 
    L2 
    LINENUMBER 25 L2 

    NEW java/lang/StringBuilder 
    DUP 
    ALOAD 1 
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String; 
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V 
    ALOAD 2 
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; 

    ASTORE 3 
    // new StringBuilder(cip).append(ciop).toString() 
    L3 
    LINENUMBER 26 L3 

    NEW java/lang/StringBuilder 
    DUP 
    ALOAD 1 
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V 
    ALOAD 2 
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String; 

    ASTORE 4 
    L4 
    LINENUMBER 27 L4 
    RETURN 

編譯器已轉化的 「CIP + CIOP」 到 「新的StringBuilder(CIP).append(CIOP)的ToString()」。換句話說,「+」實際上是更詳細的StringBuilder習慣用法的簡寫。

+0

@Henery如果這回答您的問題,請考慮將其標記爲已接受。 – luiscubal

+2

它還將接受字符串上+操作符的右操作數的任何類型。對於類實例,它將使用Object.toString()方法,如果沒有被繼承的子類覆蓋。使用基類型,它會做類似的事情。 Object.toString(),如果沒有被覆蓋並且數組實例的輸出將不會非常有用。使用例如1 +「」不起作用,因爲一個整型實例不允許創建一個StringBuilder,試圖做整型加法instea(「」+ 1是很好的解決方法)。 –

+1

我應該指出,閱讀字節碼是回答這些問題的懶惰方式。如果你用(比如說)C或者C++來試用這種方法,那麼你最終會遇到各種不正確的想法......以及當你改變編譯器開關等時破壞的脆弱程序。獲得Java理解的正確方法是閱讀JLS或一本好的教科書...而不是字節碼。 –

0

這都是編譯器的魔力。你不能在Java中進行操作符重載。

交叉手指,希望這不是可怕的錯誤,並得到了我20個downvotes

+0

這沒有錯,但它會讓你低估不確定的情況。 –

+0

@owlstead我只是有點笑。很確定我在這裏說的是什麼,但我並不那麼自大,以至於即使我最堅定的信念也不能建立在搖搖欲墜的基礎之上。 –

+2

投票決不應基於某人對其答案的信心;相反,他們應該完全基於答案的有用性。在我看來,如果有人對他們的回答大多有信心,但仍然不確定,我想知道!這對我更有用。這就是說,只要你不確定,你就不得不問自己需要做什麼才能讓自己完全確定。在這種情況下,它將諮詢JLS。如果你希望最有用的話,你可以在發佈之前或之後立即做。 – corsiKa

1

Java確實支持有限的運算符重載...對於具有某些(原始)操作數類型組合的內建運算符。主要情況如下:

  • 算術運算符對不同的數字基元類型有重載。 '+'運算符也被重載用於字符串連接。

  • '&','|','^'和'!' (非短路)邏輯和按位整數運算過載。

然而,Java 支持任何形式的程序員定義操作或操作符重載。


答案說重載是「編譯器魔術」或「編譯器做它」缺少重點。 Java語言規範說,它是語言的一部分,它的含義和(幾乎)強制應該如何實現。


作爲另一個答案指出,自動裝箱/拆箱和其他東西(嚴格地說)轉換,不超載。因此,例如:

int j = ... 
Integer i = ... 
j = j + i; 

這使用(int, int)超載的「+」操作符,並使用自動拆箱到第二個操作數轉換爲int。

byte b = ... 
j = j + b; 

這使用(int, int)超載的「+」操作符的,並使用一個投給第二個操作數轉換爲int。

注意,JLS規定了用於決定是基於(初始),該過載操作者使用的類型操作數的規則。因此,在第二個示例中,JLS強制要求使用「+」的過載,而不是過載(byte, byte)

+0

我沒有說編譯器在做運算符重載。我說它是在內部將該短語轉換爲StringBuilder.append()調用。根本不是一回事。 –

+0

@斯科特安德森 - 但你仍然缺少真正的觀點。 OP需要知道這不僅僅是一些聰明的編譯器東西。這是JLS的東西,他應該參考JLS(或一本好的Java教科書)來真正理解這裏發生的事情。 [閱讀字節碼適用於那些懶得閱讀JLS的懶惰人士;-)] –

+0

需要採取的措施,參見上文,但很多(大多數?)人從一個實際例子中學習得最好,而不是理論。從概念上講,JLS說有一件事發生,但接着說,「呃,實際上你可以爲了優化而這樣做。」 –