Причина для приоритета instanceof/
В обоих С#/Java приоритет оператора is
соответственно instanceof
приводит к некоторым уродливым необходимым скобкам. Например, вместо записи if (!bar instanceof Foo)
вам нужно написать if (!(bar instanceof Foo))
.
Итак, почему языковые команды решили, что !
имеет более высокий приоритет оператора, чем /instanceof? По общему признанию, в С# вы можете перезаписать operator!
, что приведет к другому результату в некоторых ситуациях, но эти ситуации кажутся чрезвычайно редкими (и неинтуитивными в любом случае), в то время как случай проверки того, что что-то не является типом или подтипом что-то гораздо более вероятно.
Ответы
Ответ 1
Теория заговора:
Дизайнеры С# не хотят, чтобы вы использовали оператор is
. Использование этого оператора часто является запахом плохого дизайна ООП. Если вы часто используете его часто, это, вероятно, означает, что иерархия классов неверна, и вам нужно больше полагаться на виртуальные методы и шаблоны. Дизайнеры Java пошли еще дальше: они назвали оператор instanceof
, чтобы вы съедали каждый раз, когда используете его.
На самом деле это маловероятно. Существует много случаев, когда разработчики языка и библиотеки делают некоторые функции неудобными в использовании. Некоторые примеры: кодировки символов в .NET(вы всегда должны использовать Unicode), goto
в Pascal (вы должны его избегать) и т.д. Иногда это вызвано плохим дизайном (например, WPF в .NET), но иногда он преднамеренным.
Ответ 2
В Java instanceof
является одним из реляционных операторов и имеет тот же приоритет, что и другие:
RelationalExpression:
ShiftExpression
RelationalExpression < ShiftExpression
RelationalExpression > ShiftExpression
RelationalExpression <= ShiftExpression
RelationalExpression >= ShiftExpression
RelationalExpression instanceof ReferenceType
С этой точки зрения имеет смысл, что эти две строки должны следовать одной и той же структуре:
if (!(a instanceof b))
if (!(a < b))
Ответ 3
Вот мои мысли по этому вопросу без авторитетного источника.
instanceof
- очень большой оператор. Большинство операторов не более двух символов. Кроме того, instanceof
должно иметь пробелы между ним и переменной. Из-за этих двух уникальных вещей, когда вы смотрите на выражение типа !bar instanceof Foo
, instanceof
, естественно, разделяет !bar
и Foo
, и многие люди посчитают удивительным, если !bar
выражение.
Подобные линии мыслей также могут применяться к is
, с дополнительным аргументом только того, что уже сделала Java.
Ответ 4
Я думаю, что это просто исторический. Если я правильно помню в первых версиях Java, вы даже не могли писать if(a instanceof Foo || a instanceof Bar)
без круглых скобок. Я думаю, что произошли изменения вокруг Java 2. Я не знаю, почему они не поставили его на более высокий приоритет (например, выше, чем логический). Может быть, потому, что это будет мешать оператору typecast и, таким образом, нарушить совместимость тогда?
С#, похоже, только что использовал тот же приоритет, что и Java.
Я по-прежнему считаю, что это также ошибка, чтобы сохранить приоритет побитового и/или на том же уровне, что и логический и/или. Мне нужно писать такие вещи, как if( (x&(FLAG1|FLAG2)) != 0) …
.
Ответ 5
Потому что, написав if (!bar instanceof Foo)
, он отменяет строку, а затем ищет instanceof. потому что это самый левый оператор, и я не думаю, что экземпляр даже имеет приоритет
то if (!(bar instanceof Foo))
он делает его instanceof первым, а затем отрицает все это.
если вам нужно отменить бар, а затем проверить экземпляр, тогда выполните ((!bar) instanceof Foo)
Ответ 6
-
instanceof
- очень длинное слово по сравнению с базовыми операторами типа +
или ++
. Когда вы читаете условие, вы просто потеряли фокус, по крайней мере, я это делаю.
- Он окружен пробелами, которые могут повысить читаемость, но, с другой стороны, вы не можете подключить его к другим операндам, например. подобный
5+6
может сделать.
Я считаю, что ребята решили сказать: ok, более низкий приоритет, поэтому каждый должен предоставить скобки, чтобы быть уверенным, что происходит
Ответ 7
Честно говоря, выражение типа !b instanceof SomeType
(read: "negate b
, а затем проверить, имеет ли результирующее значение тип SomeType
" ), не имеет особого смысла в Java:
Логически, b
должен был быть каким-то булевым объектом (так что !
работает), и даже если вы отрицаете его значение, оно все равно будет логическим значением того же типа, что и раньше, поэтому зачем беспокоиться отрицая это в первую очередь?
(На самом деле вы даже не можете этого сделать: b
не может быть boolean
, потому что instanceof
требует, чтобы он был реальным Object
, но опять же, если b
является boolean
, !b
все равно будет оцениваться примитивным boolean
, поэтому instanceof
не работает.)
Поэтому мы можем сказать, что !b instanceof SomeType
вообще не имеет смыслового значения в Java. Поэтому мы могли бы переназначить его значение, чтобы "проверить, не имеет ли b
типа SomeType
" - не можем ли мы?
Учитывая, что это могло быть изменено семантически и все еще не было сделано, я оставляю за собой заключение, что это не было действительно преднамеренным, но была более прагматичная причина пойти с более низким приоритетом для instanceof
:
В верхней части моей головы я подозреваю, что синтаксический анализ усложняется, если вы дадите instanceof
более высокий приоритет, чем унарный оператор !
. Вы можете проверить это.
С другой стороны, если !b instanceof SomeType
означало бы "проверить, не имеет ли b
типа SomeType
", это все равно может заставить начинающих программистов думать, что !
работает на b
, когда на самом деле это отрицает результат instanceof
, поэтому он менее двусмыслен, чтобы оставить !b instanceof SomeType
существенно undefined.
Ответ 8
instanceof
является двоичным оператором.
!
является унарным оператором.
Было бы очень сложно использовать instanceof
для соединения более жестко, чем !
.
Классическим примером путаницы является **
и -
в Python, где мы имеем:
-1 ** 2 == -(1 ** 2) # true
Я не знаю о вас, но это просто смешно для меня в Python, поэтому я рад, что они не делают то же самое на Java.
Другой пример Python:
False is (not None) # false
и
False is not None # true
который, как мне кажется, в равной степени запутан, на этот раз, потому что is
и is not
- разные операторы.
Ответ 9
Потому что язык программирования C получил это неправильно, а Java слепо следовать C.
В C,! и ~ имеют одинаковый приоритет. На практике это фактически не имеет большого значения, поскольку пишет < б
скорее, чем ! (А >= б).
Но нет никакого оператора.
Вы также можете спросить, почему /*/* */*/не гнездо правильно. Или почему Java рассчитывает от 0. Или почему должно быть ключевое слово void. Или почему Java использует ужасную {{} {}} нотацию вместо endif (или fi). Это все наследие C.
И, возможно, не зря. C программисты будут утверждать, что все эти вещи являются правильным подходом, потому что это то, к чему они привыкли. И первая работа Java должна была стать замеченной и использоваться, в отличие от многих других давно забытых языков программирования.
Будьте благодарны, что Java не имеет нулевых завершенных строк.