Операторы сравнения, <, >, <=, >=, ==, !=, возвращают результат типа boolean, то есть true или false. Эти операторы обычно используются в условных конструкциях (например, if () или циклы). Существует три типа сравнения:
- порядковое (ordinal) тестирует относительные значения числовых операндов.
- объектно-ориентированное определяет тип объекта во время исполнения программы.
- операторы равенства тестируют, одинаковы ли два значения, в том числе и нечисленные.
Рассмотрим их все подробнее.
Порядковые операторы (<, >, <=, >=)
К порядковым операторам относятся < (меньше), > (больше), <= (меньше либо равно), >= (больше либо равно). Они применяются ко всем численным типам и типу char и возвращают результат boolean. Например, если у нас имеются следующие объявления:
int p = 9;
int q = 65;
int r = -12;
float f = 9.0F;
char c = ‘A’;
то следующие тесты возвратят true:
p < q
f < q
f <= c
c > r
c >= q
Заметьте, что, когда эти операторы используются, применяется арифметическое распространение. Например, будет ошибкой присвоение значение 9.0F типа float переменной c типа char. Но к этой паре может быть применено сравнение! Для этого Java распространяет меньший тип к большему типу. То есть значение 'A' типа char (представляемое значением 65 в Unicode) распространяется до float 65.0F. Сравнение затем выполняется на результирующей паре значений float.
Порядковые сравнения не могут быть применены к объектным типам!
Оператор instanceof
Оператор instanceof тестирует класс объекта в момент исполнения программы (runtime). Левый операнд - любое выражение объектного типа (переменная или массив). Правый операнд - имя класса, интерфейса или массивный тип. Однако, левым операндом не может быть объект типа java.lang.Class, а правым операндом не может быть String.
Фрагмент кода ниже показывает пример использования оператора instanceof. Предположим, что существует класс Person с подклассом Parent:
1. public class Classroom {
2. private Hashtable inTheRoom = new Hashtable();
3. public void enterRoom(Person p) {
4. inTheRoom.put(p.getName(), p);
5. }
6. public Person getParent(String name) {
7. Object p = inTheRoom.get(name);
8. if (p instanceof Parent) {
9. return (Parent)p;
10. }
11. else {
12. return null;
13. }
14. }
15. }
Метод getParent() в строках 6-14 проверяет, содержит ли Hashtable родителя со специфическим именем. Для этого в Hashtable сначал ищется элемент со специфическим именем родителя. А потом проверяется, является ли этот элемент объектом типа Parent. Оператор instanceof проверяет, совпадает ли класс левого операнда с названием класса, заданного правым операндом или является его подклассом.
Правый операнд также может быть и названием интерфейса. И в этом случае оператор определяет, имплементирует ли левый аргумент данный интерфейс.
Опертор также используется для тестирования, является ли объект массивом. Поскольку массивы в Java являются объектами, то такое тестирование логично. Но тест проводится в два шага: (1) является ли объект массивом и (2) является ли тип элементов массива (под)классом правого аргумента. Это отражает идею, что массив, скажем, объектов типа Button (кнопки) является массивом объектов типа Component (компоненты), поскольку Button - это Component. Тест для такого массива будет выглядеть так:
if (x instanceof Component[])
Заметьте, что невозможно провести тестирование для "любого массива с элементами любого типа". То есть следующая строка недопустима:
if (x instanceof [])
Недопустимо также тестирование на массив с элементами типа Object:
if (x instanceof Object [])
поскольку элементы массива могут быть примитивного типа и тест, попросту, не сработает.
А как же протестировать, является ли объект массивом без привязки к типу его элементов? Допустим myObject это массив. Тогда следующая строка возвратит true:
myObject.getClass().isArray()
Если левый операнд равен null, то instanceof возвратит false. Никокого исключения не возникнет.
Операторы равенства (== и !=)
Операторы == и != тестируют, соответственно, равенство или неравенство. Для примитивных типов концепция равенства или неравенства достаточно тривиальна. Как и в случае с операторами порядка, операнды распространяются до наибольшего. Например, значение 10.0 типа float равно значению 10 типа byte. Для значений объектного типа, сравниваемая величина - это ссылка на объект, то есть адрес памяти.
Никогда не используйте операторы равенства для сравнения объектных типов (например строк)! Потому что они возвращают true только если адрес памяти совпадает, а не поля объектов совпадают. Для сравнения объектов используется метод equals().
- Аргумент для equals() должен быть объект типа Object. Не поддавайтесь искушению вставить аргумент того же типа, что и класс. Иначе вы перегрузите (overload) метод, а не переопределите (override) его. В итоге функциональность других частей кода, зависящих от equals() будет неправильна. Например, итерации по HashMap, то есть containsKey() и get(), будут неправильны.
- equals() должен быть коммутативным оператором. То есть результат x.equals(y) должен быть равен результату y.equals(x).
- Если вы лпределяете equals() в своём классе, то вы должны определить и hashCode(), который возвращает одно и то же значение для объектов, сравниваемых методом equals(). Это, опять таки, нужно для правильного функционирования итераций по контейнерам. Минимально допустимое поведение hashCode() - это return 1. Конечно, при такой имплементации потеряются все преимущества "настоящего" хеширования и HashMap будет просто связным списком. Но, по крайней мере, функциональность будет корректной.
Комментариев нет:
Отправить комментарий