2013-08-23 19 views
19

在兩個C#/ Java中,運算符優先級分別爲isinstanceof導致一些醜陋的必要括號。例如,不要編寫if (!bar instanceof Foo),你必須編寫if (!(bar instanceof Foo))instanceof /的優先級的原因是

那麼爲什麼語言團隊認爲!的運算符優先級高於/ instanceof?無可否認,在C#中,您可以覆蓋operator!,這會在某些情況下導致不同的結果,但這些情況似乎非常罕見(並且在任何情況下都非直觀),而檢查某些內容是否不是某種類型或子類型的情況是更有可能。

+0

這不應該在[programmers.stackexchange.com](http://programmers.stackexchange.com/)上結束嗎? – Adrian

+1

@Adrian Imo這裏比較適合,我在程序員的描述中沒有看到關於語言理論的任何內容。 – Voo

回答

11

陰謀論:

C#設計不希望你用is運營商。這個操作符的使用往往是一個糟糕的OOP設計的氣味。如果你經常使用它,這可能意味着你的類層次結構是錯誤的,你需要更多地依賴虛擬方法和模式。 Java設計師走得更遠:他們給運營商instanceof命名,讓你每次使用它都會畏縮。

實際上這不是不太可能。很多情況下,語言和圖書館設計者使用某些不方便使用的功能。一些例子:.NET中的字符編碼(你應該總是使用Unicode),goto在Pascal(你應該避免它)等。有時它是由不好的設計(如.NET中的WPF)引起的,但有時它是故意的。

+1

這實際上是一個非常好的理由,我同意這不是很牽強。 Java和C#都竭盡全力將程序員推向特定的編程風格,並避免這個運算符當然適合於此。 – Voo

1

因爲通過編寫if (!bar instanceof Foo)它否定了欄,然後查找instanceof。因爲這是最左邊的聲明,我不認爲這個instanceof甚至有優先

然後if (!(bar instanceof Foo))它使它首先instanceof,然後否定整個事情。

如果你需要否定欄,然後檢查是否有實例,然後做((!bar) instanceof Foo)

+4

是的,我瞭解運算符優先級如何工作的基礎知識。問題在於爲什麼運營商的優先選擇是以這種方式選擇的。顯然,你不必編寫'5 +(2 * 3)'來得到11而不是21的正確結果 - 這完全是因爲正確選擇了運算符優先級(顯然,「正確」只適用於特定的整數域) 。同樣可以在這裏完成 - 或者不是?這就是問題所在。 – Voo

+0

否定一個對象意味着什麼? – asteri

+0

否定一個對象只有在它有一個隱式可轉換布爾值時纔會有效,我會想到的。 – Adrian

10

這裏是我的,沒有權威的來源此事的看法。

instanceof是一個非常大的運算符。大多數操作員最多隻有兩個字符。此外,instanceof必須在它與變量之間有空格。由於這兩件獨特的事情,當你看到像!bar instanceof Foo這樣的表達式時,instanceof似乎自然將!barFoo分開,如果!bar不是子表達式,許多人會發現它很驚訝。

類似的思路也可以應用於is,其附加參數僅僅是關於Java已經做了什麼。

16

在Java中,instanceofrelational operators之一,並具有相同的優先級其他的人:

RelationalExpression: 
    ShiftExpression 
    RelationalExpression < ShiftExpression 
    RelationalExpression > ShiftExpression 
    RelationalExpression <= ShiftExpression 
    RelationalExpression >= ShiftExpression 
    RelationalExpression instanceof ReferenceType 

從這個角度來看,它是有道理的,這兩條線應該遵循相同的結構:

if (!(a instanceof b)) 
if (!(a < b)) 
+2

當然,但這只是技術上的原因,即它是如何實現的(實際上我發現你很難將它的實例放入關係運算符中),但不是它們爲什麼將它放在那裏。 – Voo

+0

RelationExpression是唯一對instanceof(IMO)有意義的類別。一種選擇是創建一個特定的類別。 – assylias

1
  1. instanceof很長字比較基本的運營商如+++。當你閱讀條件時,你只是失去了焦點,至少我是這樣做的。
  2. 它被可以增加可讀性的空格所包圍,但另一方面,您無法將其與其他操作數(例如,文本框)連接起來。像5+6可以做。

我相信,你們決定說:確定,優先級較低所以每個人都必須提供括號可以肯定這是怎麼回事

3

我認爲這只是歷史。如果我在Java的第一個版本中沒有記錯的話,你甚至不會寫沒有括號的if(a instanceof Foo || a instanceof Bar)。我想圍繞Java 2發生了一些變化。我不知道爲什麼他們沒有把它放在更高的優先級上(例如高於邏輯)。也許是因爲它會干擾類型轉換運算符,從而破壞兼容性呢?

C#似乎剛剛使用與Java相同的優先順序。

我仍然認爲保持按位和/或與邏輯和/或相同級別的優先級是一個錯誤。不得不寫if((x&(FLAG1|FLAG2)) != 0) …這樣的東西很煩人。

1

Obiously,像!b instanceof SomeType(讀:「否定b,然後檢查結果值SomeType型」)的表達式不作在Java中多大意義:

從邏輯上講,b必須是某種的布爾對象(所以!工作),即使你否定它的值,它仍然是一個布爾值,與以前相同的類型,所以爲什麼要首先否定它呢?

(實際上,你甚至不能做到這一點:b不能是boolean,因爲instanceof要求它是一個真正的Object,但話又說回來,如果bBoolean!b仍然想要得到一個原始boolean,因此instanceof不起作用。)

因此,我們可以說!b instanceof SomeType在Java中根本沒有語義含義。所以我們可以重新分配它的含義來「檢查b是不是SomeType」 - 我們不能嗎?

鑑於這可能已經改變語義,仍然沒有這樣做給我留下的結論是,這是不是真的故意的,但有一個更加務實的理由去與優先級低的instanceof

關閉我的頭頂,我會懷疑如果您給予instanceof更高的優先級比一元運算符!解析更復雜。你可能想檢查一下。

在另一方面,如果!b instanceof SomeType將意味着「檢查bSomeType類型不是」,這仍然可以欺騙新手程序員,以爲!b操作時,實際上它否定了instanceof的結果,所以它不太曖昧離開!b instanceof SomeType本質上未定義。

1

instanceof是一個二元運算符。 !是一元運算符。

這將是非常容易混淆instanceof綁定比!更緊密。
混亂的一個典型的例子是**和Python中,我們有-

-1 ** 2 == -(1 ** 2) # true 

我不知道你怎麼想,但是這只是看起來可笑我在Python,所以我很高興他們在Java中不會做同樣的事情。

另一個Python的例子是:

False is (not None) # false 

False is not None  # true 

我認爲這是同樣令人困惑,因爲這個時候isis not是不同的運營商。

0

因爲C編程語言弄錯了,所以Java一直跟着C。

在C,!和〜是相同的優先順序。在實踐中,它在C中並不重要,因爲它寫 a < b 而不是 !(a > = b)。

但沒有操作員沒有實例。

你也許會問爲什麼/ */* */* /不能正確嵌套。或者爲什麼Java從0開始計數。或者爲什麼需要有一個void關鍵字。或者爲什麼Java使用可怕的{{} {}}符號而不是endif(或fi)。這都是C的遺產。

也許有很好的理由。 C程序員會爭辯說,所有這些事情都是正確的方法,因爲這是他們習慣的。 Java的第一份工作是被注意和使用,不像許多其他已久的被遺忘的編程語言。

非常感謝Java沒有以null結尾的字符串。