[英]Why is the following Java program giving strange output?
我在Java Puzzlers中找到了下面的謎題,
public class DosEquis {
public static void main(String[] args) {
char x = 'X';
int i = 0;
System.out.print(true ? x : 0);
System.out.print(false ? i : x);
}
}
我嘗試了這個代碼並運行它,但輸出不是按照我的猜測來的,
我的猜測輸出應該是: XX
但是在
現實輸出是: X88
我努力了解但我不能,任何人都能給我們解釋一下嗎? 為什么不同的產出即將到來? 因為我能夠理解第一個print()
將打印變量char x
字符值,但是第二個print()
打印88
在char x
的ASCII表示值。如果我簡化第二個print()
的三元運算符表達式這個
if(false){
System.out.print(i);
}else{
System.out.print(x);
}
然后輸出即將來臨XX
,很奇怪,任何人都可以解決這個問題嗎?
對我來說理解三元運算符會很有幫助。
提前致謝!
這種行為的原因是三元組有一種結果類型,編譯器必須提前選擇,並且響應中調用print
的風格。
true ? x : 0
true ? x : 0
case, 0
被視為char
值,並調用print(char)
。 在第二種情況下,由於i
是一個int
, x
也被隱式轉換為int
(擴展轉換)並調用print(int)
,從而產生數字輸出。 相反,隱含地將i
為char
是非法的,因為它可能會失去精確度。
靜態解析類型的含義可以用這個例子顯示 - 不是用print
,因為有print(Object)
,但考慮一下:
void method(boolean b);
void method(Integer i);
...
method(cond? false:0);
無論cond
是什么,都存在與參數兼容的過載。 但是,編譯器需要選擇一個重載,這在編譯時是不可能的。 編譯器將自動進行同步並將表達式指定為Object
*,但沒有method(Object)
。
*實際上,我的編譯器說“類型Test中的方法方法(布爾值)不適用於參數( Object&Serializable&Comparable <?> )”,但重點是。
無論您看到什么結果,都符合JLS 15.25中規定的用於確定條件操作類型的規則。 以下是它提到的觀點:
如果第二個和第三個操作數具有可轉換的類型(第5.1.8節)到數字類型,那么有幾種情況:
如果其中一個操作數的類型為字節或字節,另一個操作數的類型為short或Short,則條件表達式的類型為short。
如果其中一個操作數是T類型,其中T是byte,short或char,另一個操作數是int類型的常量表達式(第15.28節),其值可以在類型T中表示,那么條件表達式的類型是T.
如果其中一個操作數是T類型,其中T是Byte,Short或Character,另一個操作數是int類型的常量表達式(第15.28節),其值可以在類型U中表示,這是應用拆箱的結果轉換為T,則條件表達式的類型為U.
否則,二進制數字提升(第5.6.2節)將應用於操作數類型,條件表達式的類型是第二個和第三個操作數的提升類型。
在你的問題中,遵循最后一點。 x
是char
類型,而i
是int
類型,因此x
被提升為int
。 因此第二行的輸出是88
,這是char X
的int
轉換。
要了解這里發生的事情,我們需要跟蹤類型。 讓我們依次考慮每個print語句,首先:
System.out.print(true ? x : 0);
這里的類型是布爾值? char:const int
編譯器希望ternary語句返回單個類型,它不能返回char或int。 它發現0可以轉換為char常量,因此將其視為'boolean? char:char'。 最后一個char的值為零。 因為布爾值為true,所以第一個char打印為X.
System.out.print(false ? i : x);
這里的類型是布爾值? int:char,int是一個int變量,不能被視為char,因此編譯器的選擇是錯誤,因為類型不同,縮小int或加寬char。 縮小int將會失去精度,因此編譯器不會在我們的后面執行它(它需要顯式轉換)。 加寬不會松散精度,因此char被轉換為int。 'X'的int值是88.因此打印值88。
有關此轉換過程的更多詳細信息,請參閱此處: Java語言規范
在這一行:
System.out.print(false ? i : x);
X被轉換為int,這就是打印char X的十進制值
當您使用三元運算符條件?valTrue:valFalse。 這將在兩種情況下返回相同的數據類型(true或false)。 在System.out.print(condition? i : x);
中行System.out.print(condition? i : x);
如果為true則為aspecting int,如果為false則為Char,但在這兩種情況下它只返回int。 類似於System.out.print(condition? x : i);
在bothe的情況下,它將返回Char。
在第一個表達式中,一邊是char, 0
可以賦給 char
; 因此第一個三元表達式是char。 char zero = 0;
在第二個中有int和char,並且char被加寬 : (int)'X'
是88。
常數如c ? "" : null
c ? "" : null
因此不要創建一個Object而是一個String(這里)。
你的觀察是正確的。 但是三元運算符處理相同的數據類型。 它會考慮真實值的數據類型,並在需要時轉換假值的類型。 在第一個print語句的情況下,三元運算符將數據類型視為Char作為x的數據類型,在第二個print語句中,三元運算符將數據類型視為int作為i的數據類型,這是您獲得ASCII的原因char x中值的表示。
System.out.print(true ? x : 0);
/*ternary operator(compiler) consider the resulting data
type as char as the true Value type is char.*/
System.out.print(false ? i : x);
/*ternary operator(compiler) consider the resulting data
type as int as the true Value type is int.*/
/* but if you replace the print statement with if else condition
then there is no point of ternary concept at all*/
在這樣輸入的三元語句中:( (boolean ?
if type :
else type )
,只有if類型和else類型對於確定最終類型很重要。 編譯器處理如下情況:
我們來看看這些不同的版本:
System.out.println(true ? x : 0); //X
這變為X
因為if類型是char
,而else類型是可以表示0
任何類型。 常量0
在char
數據范圍(0到65,535)內有效。 可以將x
和0
視為int
,但int
數據范圍更高(-2 31到2 31 -1)。
根據第4點 ,編譯器選擇較低范圍( char
)的類型。
System.out.println(true ? x : i); //88
這里, if類型是char, else類型是int
。 當您將變量聲明為非final int
,編譯器無法確定該值是否永遠不會從0
更改(即使您的代碼在任何地方都沒有更改!)。
因此,這里僅適用第2點 。 if類型 char
可以轉換為else類型 int
而不會有任何精度損失(因為int
具有更高的范圍),但是如果else類型 int
轉換為if類型 char
,則較低范圍的char
可能導致精度損失( i
值可能超出char
的范圍。
因此,編譯器選擇int
以避免精度損失,如第2點所示 。
一些其他測試用例(與上面已經解釋的類似的原因):
System.out.println(false ? i : x); //88 (as per point 3)
System.out.println(false ? 0 : x); //X (as per point 4)
但是,在此代碼中,結果是不同的:
final int i = 0;
System.out.println(true ? x : i); //X
System.out.println(false ? i : x); //X
你能說出原因嗎?
* 注意:所有類型最終都可以無損地轉換為Object
,包括可以自動裝箱的原始類型(在最近的Java版本上)。 如果方法被重載以接受Object
類型,則可能永遠不會遇到這種情況,因為編譯器將最終類型轉換為Object
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.