Руководство по Java Core. Базовые операторы. – PROSELYTE
Для манипулирования переменными в языке Java предусмотренно множество операторов. Все операторы мы модем поделить на такие группы:
- Арифметические операторы
- Операторы сравнения
- Битовые операторы
- Логические операторы
- Операторы присваивания
- Другие
Рассмотрим эти группы отдельно.
Арифметические операторы
Этот тип операторов используется для математических операций.
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20.
Примеры:
+ (Сложение) | A + B = 70 |
– (Вычитание) | A – B = 30 |
* (Умножение) | A * B = 1000 |
/ (Деление) | A / B = 2 |
% (Остаток от деления) | A % B = 10 |
++ (Инкремент) | A++ = 51 |
— (Декремент) | B– = 19 |
Операторы сравнения
Результатом оператора сравнения является логический тип boolean, который говорит нам, является ли данное утверждение правдой (true) или ложью (false).
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20.
Примеры:
== (Равен) | (A == B) -> false |
(A != B) -> true | |
> (Больше, чем) | (A > B) -> true |
< (Меньше, чем) | (A < B) -> false |
>= (Больше, чем или равно) | (A >= B) -> true |
<= (Меньше, чем или равно) | (A <= B) -> false |
Битовые операторы
В языке Java существует ряд битовых операторов, которые поддерживают целочисленные типы данных.
Битовые операторы позволяют нам выполнять побитовые операции.
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20. B) -> 0010 0110
Логические операторы
В языке Java поддерживаются 3 логических оператора, все они приведены таблице ниже.
Представим, что у нас есть две логические переменные (boolean) T = true и F = false.
&& (Логическое ‘И’) | (A && B) -> false |
|| (Логическое ‘ИЛИ’) | (A || B) -> true |
! (Логическое ‘НЕ’) | !(A || B) -> false |
Операторы присваивания
В языке Java есть 11 операторов присваивания. Рассмотрим их на примерах.
Представим, что у нас есть две целочисленные переменные (int) A = 50, B = 20 и некая переменная С, значение которой, пока не присвоено.
= | С = A + B ( C == 70 ) |
+= | A += B (A == 70) |
-= | A -= B (A == 30) |
*= | B *= A (B == 1000) |
/= | A /= B (A == 2) |
%= | A %= B (A == 10) |
<<= | B <<= 2 (B == 80) |
>>= | A >>= 2 (A == 12) |
&= | B &= 2 (B = B & 2 ) |
^= | A ^= 2 (A == 48) |
|= | A |= 3 (A == 51) |
Другие
К другим операторам в языке Java относится только 1. Это тернарный оператор ветвления IF.
Более подробно мы рассмотрим IF далее, а пока приведём общую форму записи:
Допустим у нас есть логическая переменная (boolean) isActive, значение которой нам неизвестно.
Пример:
int a = (isActive) ? 100 : 200.
Разъяснение:
Если isActive = true, тогда a = 100.
Если isActive = false, тогда a = 200.
В этом уроке мы рассмотрели операторы для манипулирования переменными в языке Java.
Более подробно с операторами в языке Java можно ознакомиться в спецификации языка Java (Java Language Specification).
В следующем уроке мы рассмотрим массивы в языке Java и их виды.
Ключевые слова и операторы — Kotlin
Жесткие ключевые слова (Hard Keywords)
Следующие слова всегда интерпретируются как ключевые и не могут использоваться в качестве идентификаторов:
as
- используется для приведения типов
- задает альтернативное имя для импорта
as?
используется для безопасного приведения типовbreak
завершает выполнение циклаclass
объявляет классcontinue
переходит к следующему шагу ближайшего вложенного циклаdo
начинает цикл do/while loop (цикл с постусловием)else
определяет ветвь выражения if, которое выполняется, когда условие ложноfalse
указывает значение ‘false’ типа Booleanfor
начинает цикл forfun
объявляет функциюif
начинает условное выражение ifin
- указывает объект, который перебирается в цикле for
- используется как инфиксный оператор для проверки того, что значение принадлежит диапазону, коллекции или другого объекта, который определяет метод ‘contains’
- используется в выражениях when с той же целью
- отмечает параметр типа как контравариантный
!in
- используется в качестве оператора для проверки того, что значение не принадлежит диапазону, коллекции или другой объекта, который определяет метод ‘contains’
- используется в выражениях when с той же целью
interface
объявляет интерфейсis
- проверяет, что значение имеет определенный тип
- используется в выражениях when с той же целью
!is
- проверяет, что значение не имеет определенный тип
- используется в выражениях when с той же целью
null
константа, представляющая ссылку на объект, которая не указывает ни на один объектobject
объявляет класс и его экземпляр одновременноpackage
указывает пакет для текущего файлаreturn
по умолчанию производит возврат из ближайшей окружающей его функции или анонимной функцииsuper
- ссылается на реализацию суперкласса метода или свойства
- вызывает конструктор суперкласса из вторичного конструктора
this
- относится к текущему приемнику
- вызывает другой конструктор того же класса из вторичного конструктор
throw
вызывает исключениеtrue
задает значение ‘true’ типа Booleantry
начинает блок обработки исключенийtypealias
объявляет псевдоним типаval
объявляет свойствотолько для чтения или локальную переменнуюvar
объявляет изменяемое свойство или локальную переменнуюwhen
начинает выражение when (выполняет одну из заданных ветвей)while
начинает цикл while (цикл с предусловием)
Мягкие Ключевые Слова (Soft Keywords)
Следующие слова действуют как ключевые в контексте, когда они применимы и могут использоваться как идентификаторы в других контекстах:
by
- делегирует реализацию интерфейса другому объекту
- делегирует реализацию методов доступа для свойства другому объекту
catch
начинает блок, который обрабатывает определенный тип исключенияconstructor
объявляет первичный или вторичный конструкторdelegate
используется в качестве целевого объекта аннотацииdynamic
ссылается на динамический тип в Kotlin/JS кодеfield
используется в качестве целевого объекта аннотацииfile
используется в качестве целевого объекта аннотацииfinally
начинает блок, который всегда выполняется при выходе из блока tryget
- объявляет геттер свойства
- используется в качестве целевого объекта аннотации
import
импортирует объявление из другого пакета в текущий файлinit
начинает блок инициализацииparam
используется в качестве целевого объекта аннотацииproperty
используется в качестве целевого объекта аннотацииreceiver
используется в качестве целевого объекта аннотацииset
- объявляет сеттер свойства
- используется в качестве целевого объекта аннотации
setparam
используется в качестве целевого объекта аннотацииwhere
задает ограничения для параметра универсального типа
Модификаторы (Modifier Keywords)
Следующие слова действуют как ключевые в списках модификаторов объявлений и могут использоваться как идентификаторы в других контекстах:
actual
означает реализацию Платформы в мультиплатформенных проектахabstract
обозначает класс или элемент как абстрактныйannotation
объявляет класс аннотацииcompanion
объявляет объект-компаньонconst
помечает свойство как константу времени компиляцииcrossinline
запрещает нелокальные возвраты в лямбде, передаваемом встроенной функцииdata
указывает компилятору генерировать канонические элементы для классаenum
объявляет перечислениеexpect
отмечает объявление как платформенное, ожидая реализации в модулях платформы.external
отмечает объявление как реализованное не в Kotlin (доступное через JNI или JavaScript)final
запрещает переопределение элементаinfix
позволяет вызывать функцию в инфиксной записиinline
указывает компилятору встроить функцию и лямбда-выражение на стороне вызоваinner
позволяет ссылаться на экземпляр внешнего класса из вложенного классаinternal
помечает объявление как видимое в текущем модулеlateinit
позволяет инициализировать не-null свойство вне конструктораnoinline
отключает подстановку лямбды, переданной во встроенную функциюopen
позволяет создавать подклассы класса или переопределять элементoperator
обозначает функцию как перегрузку оператора или реализацию соглашенияout
обозначает тип параметра как ковариантныйoverride
помечает элемент как переопределение элемента суперклассаprivate
помечает объявление как видимое в текущем классе или файлеprotected
помечает объявление как видимое в текущем классе и его подклассахpublic
помечает декларацию как видимую в любом местеreified
обозначает параметр типа встроенной функции, как доступная во время выполненияsealed
объявляет изолированный класс (класс с ограниченным подклассом)suspend
обозначает функцию или лямбда как приостанавливаемую (используется как сопрограмма)tailrec
отмечает функцию как с хвостовой рекурсией (позволяя компилятору заменить рекурсию итерацией)vararg
позволяет передавать нефиксированное число аргументов для параметра
Специальные идентификаторы (Special Identifiers)
Следующие идентификаторы определяются компилятором в определенных контекстах и могут использоваться как обычные идентификаторы в других контекстах:
field
используется внутри метода доступа свойства для ссылки на backing field свойстваit
используется внутри лямбды, чтобы косвенно ссылаться на ее параметр
Операторы и специальные символы (Operators and Special Symbols)
Котлин поддерживает следующие операторы и специальные символы:
+
,-
,*
,/
,%
— математические операторы*
также используется для передачи массива в параметр vararg
=
- оператор присваивания
- используется для указания значений по умолчанию для параметров
+=
,-=
,*=
,/=
,%=
— расширенные операторы присваивания++
,--
— операторы инкремента и декремента&&
,||
,!
— логические операторы ‘и’, ‘или’, ‘не’ (для побитовых операций используют соответствующие инфиксные функции)==
,!=
— операторы равенства (переведенные на вызовыequals()
для не-примитивных типов)===
,!==
— операторы ссылочного равенства<
,>
,<=
,>=
— операторы сравнения (переведенные на вызовыcompareTo()
для не-примитивных типов)[
,]
— оператор индексированного доступа (переведенный на вызовыget
иset
)!!
утверждает, что выражение не равно null?.
выполняет безопасный вызов (вызывает метод или обращается к свойству, если получатель не имеет значения null)?:
принимает правое значение, если левое значение равно нулю (Элвис оператор)::
создает ссылку на элемент или ссылку на класс..
создает диапазон:
отделяет имя от типа в объявлениях?
отмечает тип с нулевым значением->
- разделяет параметры и тело лямбда-выражения
- разделяет параметры и тип возвращаемого значения при объявлении лямбды
- разделяет условие и тело ветви выражения when
@
- вводит аннотацию
- вводит или ссылается на метку цикла
- вводит или ссылается на лямбда-метку
- ссылается на выражение ‘this’ из внешней области
- ссылается на внешний суперкласс
;
разделяет несколько операторов на одной строке$
ссылается на переменную или выражение в строковом шаблоне_
- заменяет неиспользуемый параметр в лямбда выражении
- заменяет неиспользуемый параметр в деструктуризирующем присваивании
Действительно ли == работает одинаково или по-разному при сравнении двух примитивов и двух объектов в Java? [java, object, primitive, equals-operator]
При поиске объяснений того, как логическое равенство ==
работает в Java, ответы всегда примерно такие:
- Для примитивов он возвращает, имеют ли примитивы одинаковое значение (это включает в себя сравнение примитива с его WrapperObject, поскольку WrapperObject автоматически распаковывается в примитив).
- Для объектов он возвращает, представляют ли они один и тот же объект в куче.
Но все эти объяснения, кажется, подразумевают, что это две разные вещи, что ==
ведет себя по-разному в зависимости от того, сравниваете ли вы объекты с примитивами. Мне кажется, что на самом деле они должны быть одно и то же: взять две переменные из стека и сравнить их значения.
Меняется не поведение ==
, а то, что представляют сравниваемые значения. Если вещи, которые вы сравниваете, являются примитивами, тогда значение в стеке является значением самого примитива. Если вы сравниваете объекты, то значение в стеке является значением ссылки (и, следовательно, адресом объекта в куче).
Я что-то неправильно понял, или ==
действительно ведет себя одинаково во всех ситуациях? Бонусные баллы, если вы можете указать мне на документацию о том, как это действительно работает под прикрытием.
java object primitive equals-operator
person user7382368 schedule 18. 08.2019 source источник
Ответы (2)
arrow_upward
18
arrow_downward
Как говорят другие ответы/комментарии, на уровне языка Java семантика оператора ==
указана (в JLS 15.21) независимо от реализации. Строго говоря, вы не можете вывести детали реализации «под капотом» из текста JLS. Все, что вы можете сказать, это то, что любая совместимая реализация ==
должна вести себя определенным образом.
Я предполагаю, что мы говорим об обычных JVM, где фактическим машинным представлением ссылки является машинный адрес. Можно реализовать ссылки другими способами; например, используя какой-либо механизм косвенной адресации, такой как PIDLAM.
На уровне байт-кода существует ряд различных инструкций байт-кода, которые реализуют логику ==
в зависимости от типа (int
, long
или ссылка). Однако семантика сравнений аналогична. Как только байт-коды будут проверены на безопасность типов, целые числа и адреса могут обрабатываться одинаково для целей ==
сравнения на аппаратном уровне.
На уровне аппаратных средств (машинных инструкций) ==
работает одинаково для примитивных целочисленных типов и непримитивных значений. В обоих случаях будет выполняться машинная инструкция, которая сравнивает два «слова», взятых из регистра или из памяти (кучи или стека).
Специфицированная JLS семантика ==
для float
и double
немного отличается, поскольку специальные значения (бесконечности и нечисловые значения) требуют специальной обработки. Например: NaN == NaN равно false
. См. также стандарт IEEE 754 с плавающей запятой.
Для этого существуют разные байт-коды, и на аппаратном уровне используемые инструкции отличаются от тех, которые используются в целочисленных и эталонных случаях. (Обработка специальных значений обычно выполняется на плавающем оборудовании.)
Определенная JLS семантика ==
для boolean
, byte
, short
и char
заключается в преобразовании значений в другой тип (int
, long
, float
или double
) перед их сравнением. Продвижение происходит и в других случаях, если операнды имеют разные (неупакованные) типы.
Кроме того, распаковка происходит, если упакован один (но не оба!) операнда. Если оба операнда упакованы, то ==
является эталонным сравнением.
Резюмируя вышеизложенное…
Я что-то неправильно понял или == действительно ведет себя одинаково во всех ситуациях?
Нет, если вы включаете типы с плавающей запятой и соображения расширения и распаковки примитивов.
Бонусные баллы, если вы можете указать мне на документацию о том, как это действительно работает под прикрытием.
Для этого нет официальной (Oracle) общедоступной документации. Спецификация JLS и JVM не предписывает стратегии реализации.
person Stephen C schedule 18.08.2019
arrow_upward
4
arrow_downward
Я понимаю ваше объяснение, и оно верно с учетом некоторых определений терминов. Но это не соответствует тому, как Java говорит об объектах и примитивах.
Идея «ссылки» на объект в Java серьезно преуменьшается; Я думаю, что можно быть «Java-программистом» и не совсем понимать, что такое ссылка. Вы можете запомнить правила, в которых это имеет значение — оператор ‘==’, передача параметров методам — и не понимать, как это реализовано или могло бы быть реализовано.
Поэтому я думаю, что многих людей, которые программируют на Java, смутило бы, если бы они сказали, что == «ведет себя одинаково во всех ситуациях», потому что это требует слишком много знаний «под прикрытием». Java не поощряет (и не требует) заглядывать «под одеяло» до такой степени.
person arcy schedule 18.08.2019
Равенство операторы сравнения в Java используются для равенства (==) и операции сравнения не-равно (!=). Операторы сравнения равенства могут появляться в выражении равенства: операторы сравнения на равенство равны по приоритету и оцениваются слева направо. == и != операторы сравнения могут выполнять числовые сравнения, логические сравнения и сравнения ссылочного типа. Оба этих оператора производить логические значения. Каталожные номера операторы реляционного сравнения; Порядок операций Оператор эквивалентности ==Оператор равенства == выполняет сравнение между своими операндами и возвращает логическое значение. Возвращает чистое значение true, если операнды равны друг другу; в противном случае возвращается чистое значение false. Оператор == может появляться как часть равенства выражение. Оператор равенства никогда не генерирует исключение. Операнды == могут быть любого типа, но они оба должны быть одного типа или времени компиляции возникает ошибка. Если один операнд имеет арифметический тип, то другой также должны быть арифметического типа. Если один операнд имеет тип boolean, другой также должен быть логического типа. Если один операнд является ссылочным типом, другой также должен быть ссылочным тип. Обратите внимание, что ни один из операндов не может быть выражением, вызывающим метод пустоты. Если оба операнда имеют арифметические типы, то оператор выполняет арифметическое равенство сравнение. Оператор может выполнять преобразования типов операндов:
сравнение на равенство любых двух арифметических значений дает истину тогда и только тогда, когда оба операнда имеют одно и то же значение; иначе сравнение выдает ложное. Сравнение с плавающей запятой данные регулируются следующими дополнительными правилами:
Если оба операнда являются булевыми значениями, оператор выполняет логическое сравнение на равенство. Сравнение возвращает истину, если оба операнда истинны или оба операнда ложны. В противном случае сравнение выдает ложное. Если оба операнда являются ссылочными типами, оператор выполняет сравнение объектов на равенство. Для выполнения этого типа сравнения должна быть возможность привести значение одного из операндов к типу другого операнд, или возникает ошибка времени компиляции. Сравнение дает истина, если оба его операнда относятся к одному и тому же объект или если оба его операнда равны нулю; в противном случае сравнение дает ложь. Потому что оператор == определяет, являются ли два объекта один и тот же объект, он не подходит для сравнений, которые требуют чтобы определить, имеют ли два объекта одинаковое содержимое. Например, если вам нужно знать, являются ли два объекта String содержат одинаковые последовательности символов, == оператор не подходит. Вы должны использовать equals() вместо этого метод:[4]
string1.equals (string2) // Сравнивает содержимое строк string1 == string2 // Сравнивает фактические строковые объекты Каталожные номера арифметические типы; логический тип; Ссылочные типы Неравный оператор !=Оператор не равно != выполняет сравнение между своими операндами и возвращает логическое значение ценность. Возвращает чистое значение true, если операнды не равны друг другу; в противном случае он возвращает чистый значение ложно. Оператор != может появляться как часть выражения равенства. Оператор не равно никогда не выдает исключение. Операнды != может быть любого типа, но они оба должны быть одного типа или возникает ошибка времени компиляции. Если один операнд имеет арифметическое значение тип, другой также должен быть арифметического типа. Если один операнд имеет тип boolean, другой также должен быть типа тип булев. Если один операнд является ссылочным типом, другой также должен быть ссылочным типом. Обратите внимание, что ни один из операндов может быть выражением, которое вызывает метод void. Если оба операнда имеют арифметический тип, оператор выполняет сравнение арифметического неравенства. Оператор может выполнять тип преобразования операндов:
Неравенство сравнение любых двух арифметических значений дает истинное тогда и только тогда, когда оба операнда не являются одним и тем же значением; иначе сравнение дает ложь. Сравнение данные с плавающей запятой регулируются следующими дополнительными правилами:
Если оба операнда логические значения, оператор выполняет сравнение логических неравенств. сравнение дает false, если оба операнда истина или оба операнда ложны. В противном случае сравнение дает true. Если оба операнда являются ссылочными типами, оператор выполняет сравнение объектов на равенство. Для выполнения этого вида сравнения, должна быть возможность привести значение одного из операнды к типу другого операнда или ошибка времени компиляции имеет место. Сравнение дает истину, если оба его операндов относятся к разным объектам, и если оба его операнда не являются нулевыми; в противном случае сравнение дает ЛОЖЬ. Потому что != оператор определяет, являются ли два объекта разными объектами, это не подходит для сравнений, которые должны определить, являются ли два объекта имеют разное содержание. Например, если вам нужно узнать, два объекта String содержат разные последовательности символов, оператор != не подходит. Вы должны использовать equals() вместо этого метод: [5]
!string1.equals (string2) // Сравнивает содержимое строк string1 != string2 // Сравнивает фактические строковые объекты Каталожные номера арифметические типы; логический тип; Ссылочные типы
|
[Глава 4] 4.
8 Операторы реляционного сравненияОтносительный операторы сравнения в Java используются для менее чем (<), меньше или равно (<=), больше или равно (>=), больше (>), и instanceof операции сравнения. Они может появиться в относительном выражении:
операторы реляционного сравнения имеют равный приоритет и оценивается слева направо. <, <=, Операторы >= и > являются числовыми операторы сравнения, а instanceof — это тип оператор сравнения. Все эти операторы производят логические ценности.
Каталожные номера Операторы смены; Порядок операций; Тип 3
Меньший оператор
<Оператор меньше чем < выполняет сравнение между своими операндами и возвращает логическое значение ценность. Он возвращает чистое значение true, если его левый операнд меньше правого операнда; в противном случае оператор возвращает чистое значение false. < оператор может появляться как часть реляционного выражения. оператор меньше чем никогда не генерирует исключение.
Типы оба операнда оператора «меньше» должны быть арифметическими типами, или возникает ошибка времени компиляции. Оператор < может выполнять преобразования типов для своих операндов:
- Если один из операндов имеет тип double, то другой операнд преобразуется в двойное.
- В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в число с плавающей запятой.
- В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в длинный.
- В противном случае оба операнда преобразуются в int.
сравнение любых двух арифметических значений дает истинное если значение левого операнда меньше значения правого операнд; в противном случае сравнение дает ложь. Сравнение данных с плавающей запятой регулируется следующим дополнительные правила:
- Если любой из операндов не является числом (NaN), сравнение дает false.
- Отрицательный бесконечность — самое отрицательное значение. Если левый операнд отрицательный бесконечность, сравнение дает истину, если только правый операнд также равен отрицательной бесконечности, и в этом случае сравнение выдает ложное.
- Положительная бесконечность является самым положительным значением. Если правый операнд положительная бесконечность, сравнение дает истину, если только левый операнд также положительная бесконечность, и в этом случае сравнение выдает ложное.
- Положительный и отрицательный нули считаются равными, поэтому -0,0 < 0,0 выдает ложное.
Каталожные номера Арифметические типы
Оператор «меньше или равно»
<=Оператор «меньше или равно» <= выполняет сравнение между своими операндами и возвращает логическое значение. Он возвращает чистое значение true, если его левый операнд меньше или равно своему правому операнду; в противном случае оператор возвращает чистое значение false. <= оператор может появляться как часть реляционного выражения. Оператор «меньше или равно» никогда не генерирует исключение.
типы обоих операндов оператора «меньше или равно» должны быть арифметическими типами, иначе произойдет ошибка времени компиляции. <= оператор может выполнять преобразования типов для своих операндов:
- Если один из операндов имеет тип double, то другой операнд преобразуется в двойное.
- В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в число с плавающей запятой.
- В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в длинный.
- В противном случае, оба операнда преобразуются в int.
сравнение любых двух арифметических значений дает истинное если значение левого операнда меньше или равно значению правого операнда; в противном случае сравнение дает ложь. Сравнение данных с плавающей запятой регулируется следующим дополнительные правила:
- Если любой из операндов не является числом (NaN), сравнение дает false.
- Отрицательный бесконечность — самое отрицательное значение. Если левый операнд отрицательный бесконечность, сравнение всегда дает истину.
- Положительная бесконечность — самое положительное значение. Если право операнд положительная бесконечность, сравнение всегда дает истину.
- Положительный и отрицательный нуль считаются равными, поэтому 0.0 <= -0.0 дает истину.
Каталожные номера Арифметические типы
Оператор «больше или равно» >=
Оператор больше или равно >= выполняет сравнение между своими операндами и возвращает логическое значение. Он возвращает чистое значение true, если его левый операнд больше или равно своему правому операнду; в противном случае оператор возвращает чистое значение false. >= оператор может появляться как часть реляционного выражения. Оператор «больше или равно» никогда не генерирует исключение.
Типы обоих операндов оператора больше или равно должны быть арифметическими типами, иначе произойдет ошибка времени компиляции. Оператор >= может выполнять преобразования типов на его операнды:
- Если один из операндов имеет тип double, то другой операнд преобразуется в двойное.
- В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в число с плавающей запятой.
- В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в длинный.
- В противном случае, оба операнда преобразуются в int.
сравнение любых двух арифметических значений дает истинное если значение левого операнда больше или равно значение правого операнда; в противном случае сравнение дает ложь. Сравнение данных с плавающей запятой регулируется следующим дополнительные правила:
- Если любой из операндов не является числом (NaN), сравнение дает false.
- Отрицательный бесконечность — самое отрицательное значение. Если правый операнд отрицательный бесконечность, сравнение всегда дает истину.
- Положительная бесконечность — самое положительное значение. Если левый операнд положительная бесконечность, сравнение всегда дает истину.
- Положительный и отрицательный ноль считаются равными, поэтому -0,0 >= 0. 0 дает истину.
Каталожные номера Арифметические типы
Оператор «больше чем» >
Оператор «больше» > выполняет сравнение между своими операндами и возвращает логическое значение ценность. Он возвращает чистое значение true, если его левый операнд больше правого операнда; в противном случае оператор возвращает чистое значение false. > оператор может появляться как часть реляционного выражения. Больше, чем оператор никогда не генерирует исключение.
Типы оба операнда оператора «больше» должны быть арифметическими типами, или возникает ошибка времени компиляции. Оператор > может выполнять преобразования типов для своих операндов:
- Если один из операндов имеет тип double, то другой операнд преобразуется в двойное.
- В противном случае, если один из операндов имеет тип float, другой операнд преобразуется в число с плавающей запятой.
- В противном случае, если один из операндов имеет тип long, другой операнд преобразуется в длинный.
- В противном случае оба операнда преобразуются в int.
сравнение любых двух арифметических значений дает истинное если значение левого операнда больше значения правый операнд; в противном случае сравнение дает ложь. Сравнение данных с плавающей запятой регулируется следующим дополнительные правила:
- Если любой из операндов не является числом (NaN), сравнение дает false.
- Отрицательный бесконечность — самое отрицательное значение. Если правый операнд отрицательный бесконечность, сравнение дает истину, если только левый операнд также равен отрицательной бесконечности, и в этом случае сравнение выдает ложное.
- Положительная бесконечность является самым положительным значением. Если левый операнд равен положительной бесконечности, сравнение дает истину, если только правильное операнд также положительная бесконечность, и в этом случае сравнение выдает ложное.
- Положительный и отрицательный нули рассматриваются как равные, поэтому 0,0 > -0,0 дает ЛОЖЬ.
Каталожные номера Арифметические типы
Экземпляр Оператора
Оператор instanceof выполняет сравнение типов между своими операндами и возвращает логическое значение. Возвращает чистое значение true, если объект на который ссылается левый операнд, можно привести к указанному типу как правый операнд; в противном случае оператор возвращает чистое значение ЛОЖЬ. Если значение левого операнда равно нулю, оператор instanceof возвращает чистое значение ЛОЖЬ. Оператор instanceof может появляться как часть реляционного выражения. Экземпляр оператор никогда не генерирует исключение.
Тип левый операнд экземпляра оператор должен быть ссылочным типом, иначе произойдет ошибка времени компиляции.
Все объекты наследуют метод equals(). из класса Объект. Равно () метод, определенный в классе Object, возвращает true если два сравниваемых объекта являются одним и тем же объектом. Для некоторых классов, более уместно переопределить метод equals() метод, чтобы он сравнивал содержимое двух объектов. До такой метод может выполнять сравнение, он должен проверять, что объекты являются экземплярами одного и того же класса с помощью instanceof. Например, предположим, что вы определяете класс для представления комплексные числа. Поскольку вы хотите equals() метод для сравнения содержимого комплексных числовых объектов, которые вы определяете метод equals для класса комплексных чисел это выглядит так:
логическое равно (объект о) { если (o экземпляр сложного числа) вернуть o.real == this.real && o.imaginary == this.imaginary; }
Экземпляр оператор также может использоваться, чтобы узнать, является ли объект экземпляром класса, реализующего интерфейс. Например:
if (o instanceof Runnable) (новый поток ((Runnable) o). start;
Каталожные номера Отливки; типы классов; Типы интерфейсов
Операторы
8.1. Оператор Spread
Оператор Spread-dot ( *.
), часто сокращенно просто Оператор Spread, используется для вызова действия над всеми элементами. агрегатного объекта. Это эквивалентно вызову действия над каждым элементом и сбору результата в список:
class Car { Строка сделать Струнная модель } деф автомобили = [ новый автомобиль(марка: "Пежо", модель: "508"), новый автомобиль(марка: 'Renault', модель: 'Clio')] (1) def makes = автомобили*.make (2) assert makes == ['Peugeot', 'Renault'] (3)
1 | построить список из автомобилей элементов. Список представляет собой совокупность объектов. |
2 | вызвать оператора спреда из списка, обратившись к свойству make каждого элемента |
3 | возвращает список строк, соответствующих набору make элементов |
Выражение cars*. make
эквивалентно cars.collect{ it.make }
.
Нотация Groovy GPath позволяет сократить путь, когда указанное свойство
не является свойством содержащего списка, в этом случае он автоматически
распространять. В ранее упомянутом случае выражение cars.make
может
можно использовать, хотя часто рекомендуется сохранять явный оператор с расставленными точками.
Оператор распространения является нулевым, что означает, что если элемент коллекции имеет значение null,
он вернет null вместо того, чтобы выдать NullPointerException
:
cars = [ новый автомобиль(марка: "Пежо", модель: "508"), ноль, (1) новый автомобиль(марка: 'Renault', модель: 'Clio')] assert cars*.make == ['Peugeot', null, 'Renault'] (2) утверждать null*.make == null (3)
1 | построить список, для которого один из элементов нулевой |
2 | с использованием оператора распространения вызовет , а не исключение NullPointerException |
3 | получатель также может быть нулевым, и в этом случае возвращаемое значение равно ноль |
Оператор распространения можно использовать в любом классе, реализующем интерфейс Iterable
:
class Component { Длинный идентификатор Имя строки } класс CompositeObject реализует Iterable{ Компоненты защиты = [ новый компонент (id: 1, имя: «Foo»), новый компонент (id: 2, имя: «Бар»)] @Override Итератор<Компонент> итератор() { компоненты. iterator() } } def составной = новый составной объект () утверждать составной*.id == [1,2] утверждать составное*.имя == ['Foo','Bar']
Использовать несколько вызовов оператора растровой точки (здесь cars*.models*.name
), когда
работа с агрегатами структур данных, которые сами содержат агрегаты:
class Make { Имя строки Список моделей} @канонический модель класса { Имя строки } деф автомобили = [ новая марка (название: «Пежо», модели: [новая модель('408'), новая модель('508')]), новый Марка (название: «Рено», модели: [новая модель('Clio'), новая модель('Captur')]) ] def makes = автомобили*.название assert делает == ['Peugeot', 'Renault'] def модели = автомобили*.модели*.название утверждать модели == [['408', '508'], ['Clio', 'Captur']] assert models.sum() == ['408', '508', 'Clio', 'Captur'] // выравнивание на один уровень assert models.flatten() == ['408', '508', 'Clio', 'Captur'] // выравниваем все уровни (в данном случае один)
Рассмотрите возможность использования метода collectNested
DGM вместо оператора с расставленными точками для коллекций коллекций:
class Car { Строка сделать Струнная модель } деф автомобили = [ [ новый автомобиль(марка: 'Peugeot', модель: '408'), новый автомобиль(марка: 'Peugeot', модель: '508') ], [ новый автомобиль(марка: 'Renault', модель: 'Clio'), новый автомобиль(марка: 'Renault', модель: 'Captur') ] ] def models = cars. collectNested{ it.model } утверждать модели == [['408', '508'], ['Clio', 'Captur']]
8.1.1. Распространение аргументов метода
Возможны ситуации, когда аргументы вызова метода можно найти в списке, который необходимо адаптировать к методу аргументы. В таких ситуациях вы можете использовать оператор распространения для вызова метода. Например, представьте, что у вас есть следующая подпись метода:
int function (int x, int y, int z) { х*у+г }
тогда, если у вас есть следующий список:
def args = [4,5,6]
вы можете вызвать метод без определения промежуточных переменных:
assert function(*args) == 26
Можно даже смешивать обычные аргументы с расширенными:
args = [4] функция утверждения(*args,5,6) == 26
8.1.2. Элементы списка распространения
При использовании внутри литерала списка оператор расширения действует так, как если бы содержимое элемента расширения было встроено в список:
def items = [4,5] (1) список по умолчанию = [1,2,3,*элементы,6] (2) список утверждений == [1,2,3,4,5,6] (3)
1 | элементов это список |
2 | мы хотим вставить содержимое списка элементов непосредственно в список без вызова addAll |
3 | содержимое элементов было встроено в список |
8.
1.3. Элементы карты распространенияОператор карты распространения работает аналогично оператору списка распространения, но для карт. Это позволяет вам встроить содержимое карты в другой литерал карты, как в следующем примере:
def m1 = [c:3, d:4] (1) карта защиты = [a:1, b:2, *:m1] (2) утверждать карту == [a:1, b:2, c:3, d:4] (3)
1 | m1 это карта, которую мы хотим встроить |
2 | мы используем нотацию *:m1 для распространения содержимого m1 на карту |
3 | карта содержит все элементы m1 |
Должность оператора карты спреда имеет значение, как показано в следующем примере:
по умолчанию m1 = [c:3, d:4] (1) карта защиты = [a:1, b:2, *:m1, d: 8] (2) assert map == [a:1, b:2, c:3, d:8] (3)
1 | m1 это карта, которую мы хотим встроить |
2 | мы используем нотацию *:m1 для распространения содержимого m1 на карту , но переопределить ключ d после распространяя |
3 | карта содержит все ожидаемые ключи, но d был переопределен |
8.
2. Оператор диапазона Groovy поддерживает концепцию диапазонов и предоставляет нотацию ( ..
) для создания диапазонов объектов:
def range = 0..5 (1) утверждать (0..5).collect() == [0, 1, 2, 3, 4, 5] (2) утверждать (0..<5).collect() == [0, 1, 2, 3, 4] (3) утверждать (0<..5).collect() == [1, 2, 3, 4, 5] (4) утверждать (0<..<5).collect() == [1, 2, 3, 4] (5) утверждать (0..5) instanceof List (6) утверждать (0..5).size() == 6 (7)
1 | простой диапазон целых чисел, сохраненный в локальной переменной |
2 | и IntRange с включенными границами |
3 | и IntRange с исключительной верхней границей |
4 | и IntRange с эксклюзивной нижней границей |
5 | и IntRange с исключительными нижними и верхними границами |
6 | a groovy. lang.Range реализует интерфейс List |
7 | означает, что вы можете вызвать на нем метод size |
Реализация диапазонов упрощена, что означает, что сохраняются только нижняя и верхняя границы. Вы можете создать диапазон
из любых Сопоставимый объект
, который имеет методы next()
и previous()
для определения следующего/предыдущего элемента в диапазоне.
Например, вы можете создать диапазон символов следующим образом:
assert('a'..'d').collect() == ['a','b','c','d']
8.3. Оператор космического корабля
Оператор космического корабля ( <=>
) делегирует метод compareTo
:
assert (1 <=> 1) == 0 утверждать (1 <=> 2) == -1 утверждать (2 <=> 1) == 1 утверждать ('a' <=> 'z') == -1
8.4. Оператор нижнего индекса
Оператор нижнего индекса представляет собой сокращенную запись для getAt
или putAt
, в зависимости от того, найдете ли вы его на
левая или правая часть задания:
def list = [0,1,2,3,4] список утверждений[2] == 2 (1) список[2] = 4 (2) утвердить список[0. .2] == [0,1,4] (3) список[0..2] = [6,6,6] (4) список утверждений == [6,6,6,3,4] (5)
1 | [2] можно использовать вместо getAt(2) |
2 | , если слева от задания, вызовет putAt |
3 | getAt также поддерживает диапазоны |
4 | так же как и putAt |
5 | список изменен |
Оператор нижнего индекса в сочетании с пользовательской реализацией getAt
/ putAt
является удобным способом деструктурирования
объекты:
класс пользователя { Длинный идентификатор Имя строки защита getAt(int i) { (1) переключатель (я) { случай 0: возвращаемый идентификатор случай 1: вернуть имя } выбросить новое исключение IllegalArgumentException("Нет такого элемента $i") } void putAt (int i, значение по умолчанию) { (2) переключатель (я) { случай 0: идентификатор = значение; возвращаться случай 1: имя = значение; возвращаться } выбросить новое исключение IllegalArgumentException("Нет такого элемента $i") } } def user = новый пользователь (id: 1, имя: «Алекс») (3) утвердить пользователя [0] == 1 (4) утвердить пользователя [1] == 'Алекс' (5) пользователь [1] = 'Боб' (6) утверждать user. name == 'Боб' (7)
1 | класс User определяет пользовательский getAt реализация |
2 | класс User определяет пользовательскую реализацию putAt |
3 | создать пробного пользователя |
4 | с помощью оператора индекса с индексом 0 позволяет получить идентификатор пользователя |
5 | с помощью оператора индекса с индексом 1 позволяет получить имя пользователя |
6 | мы можем использовать оператор нижнего индекса для записи свойства благодаря делегированию putAt |
7 | и проверьте, действительно ли это свойство имя было изменено |
8.
5. Оператор безопасного индексирования В Groovy 3.0.0 представлен оператор безопасного индексирования, т. е. 9.0313 ?[] , что похоже на ?.
. Например:
Строка[] массив = ['a', 'b'] assert 'b' == array?[1] // получаем с использованием индекса обычного массива array?[1] = 'c' // устанавливаем с использованием индекса обычного массива утверждать 'c' == массив? [1] массив = ноль assert null == array?[1] // возвращаем null для всех значений индекса array?[1] = 'c' // тихо игнорируем попытку установить значение утверждать массив null ==?[1] def personInfo = [имя: 'Daniel.Sun', местоположение: 'Шанхай'] assert 'Daniel.Sun' == personInfo?['name'] // используем индекс карты нормалей personInfo?['name'] = 'sunlan' // устанавливается с использованием индекса карты нормалей утверждать 'sunlan' == personInfo?['name'] информация о человеке = ноль assert null == personInfo?['name'] // возвращаем null для всех значений карты personInfo?['name'] = 'sunlan' // незаметно игнорируем попытку установить значение утверждать null == personInfo?['name']
8.
6. Оператор принадлежности Оператор принадлежности ( в
) эквивалентен вызову метода isCase
. В контексте списка
это эквивалентно
для вызова содержит
, как в следующем примере:
def list = ['Grace','Rob','Emmy'] утверждать («Эмми» в списке) (1)
1 | эквивалентно вызову list.contains('Эмми') или list.isCase('Эмми') |
8.7. Оператор идентификации
В Groovy использование ==
для проверки равенства отличается от использования того же оператора в Java. В Groovy вызов равен
.
Если вы хотите сравнить ссылочное равенство, вы должны использовать равно
, как в следующем примере:
def list1 = ['Groovy 1.8','Groovy 2.0','Groovy 2.3'] (1) def list2 = ['Groovy 1. 8','Groovy 2.0','Groovy 2.3'] (2) утверждать список1 == список2 (3) утверждать !list1.is(list2) (4)
1 | Создать список строк |
2 | Создать другой список строк, содержащих те же элементы |
3 | используя == , мы проверяем равенство объектов |
4 | , но использование равно , мы можем проверить, что ссылки различны |
8.8. Оператор приведения
Оператор приведения ( as
) является вариантом приведения. Приведение преобразует объект из одного типа в другой без их
быть совместимым для назначения. Возьмем пример:
Целое число x = 123 Строка s = (Строка) x (1)
1 | Целое число не может быть назначено String , поэтому оно создаст ClassCastException во время выполнения |
Это можно исправить, используя вместо этого приведение :
Целое число x = 123 Строка s = x as Строка (1)
1 | Целое число не может быть присвоено строке , но использование в качестве приведет к принудительному преобразованию в строку |
Когда объект принудительно преобразуется в другой, если целевой тип не совпадает с исходным типом, приведение возвращает новый объект . Правила приведения различаются в зависимости от исходного и целевого типов, и приведение может завершиться ошибкой, если не выполняется преобразование.
правила найдены. Пользовательские правила преобразования могут быть реализованы благодаря asType
метод:
класс Идентифицируемый { Имя строки } класс Пользователь { Длинный идентификатор Имя строки def asType (Цель класса) { (1) если (цель == Идентифицируемый) { вернуть новый идентифицируемый (имя: имя) } выбросить новое исключение ClassCastException («Пользователь не может быть принужден к $ target») } } def u = новый пользователь (имя: «Ксавье») (2) def p = u как идентифицируемый (3) утверждать p instanceof Идентифицируемый (4) assert !(p instanceof User) (5)
1 | класс User определяет пользовательское правило преобразования с User на Идентифицируемый |
2 | мы создаем экземпляр пользователя |
3 | мы принуждаем экземпляр пользователя к идентифицируемому |
4 | цель является экземпляром Идентифицируемый |
5 | цель не является экземпляром Пользователь Больше |
8.
9. Алмазный оператор Алмазный оператор ( <>
) является синтаксическим сахарным оператором, добавленным для поддержки совместимости с оператором
то же имя в Java 7. Оно используется для указания того, что универсальные типы должны выводиться из объявления:
Liststrings = new LinkedList<>()
В динамическом Groovy это совершенно не используется. В Groovy со статической проверкой типов это также необязательно, так как Groovy средство проверки типов выполняет вывод типа независимо от того, присутствует этот оператор или нет.
8.10. Оператор вызова
Оператор вызова ()
используется для неявного вызова метода с именем call
. Для любого объекта, который определяет метод вызова
,
вы можете опустить часть .call
и вместо этого использовать оператор вызова:
class MyCallable { внутренний вызов (int x) { (1) 2*х } } def mc = новый MyCallable() утверждать mc.