Java if instanceof string

Java instanceof Operator

The instanceof operator in Java is used to check whether an object is an instance of a particular class or not.

objectName instanceOf className;

Here, if objectName is an instance of className , the operator returns true . Otherwise, it returns false .

Example: Java instanceof

name is an instance of String: true obj is an instance of Main: true

In the above example, we have created a variable name of the String type and an object obj of the Main class.

Here, we have used the instanceof operator to check whether name and obj are instances of the String and Main class respectively. And, the operator returns true in both cases.

Note: In Java, String is a class rather than a primitive data type. To learn more, visit Java String.

Java instanceof during Inheritance

We can use the instanceof operator to check if objects of the subclass is also an instance of the superclass. For example,

// Java Program to check if an object of the subclass // is also an instance of the superclass // superclass class Animal < >// subclass class Dog extends Animal < >class Main < public static void main(String[] args) < // create an object of the subclass Dog d1 = new Dog(); // checks if d1 is an instance of the subclass System.out.println(d1 instanceof Dog); // prints true // checks if d1 is an instance of the superclass System.out.println(d1 instanceof Animal); // prints true >>

In the above example, we have created a subclass Dog that inherits from the superclass Animal . We have created an object d1 of the Dog class.

Inside the print statement, notice the expression,

Here, we are using the instanceof operator to check whether d1 is also an instance of the superclass Animal .

Java instanceof in Interface

The instanceof operator is also used to check whether an object of a class is also an instance of the interface implemented by the class. For example,

// Java program to check if an object of a class is also // an instance of the interface implemented by the class interface Animal < >class Dog implements Animal < >class Main < public static void main(String[] args) < // create an object of the Dog class Dog d1 = new Dog(); // checks if the object of Dog // is also an instance of Animal System.out.println(d1 instanceof Animal); // returns true >>

In the above example, the Dog class implements the Animal interface. Inside the print statement, notice the expression,

Here, d1 is an instance of Dog class. The instanceof operator checks if d1 is also an instance of the interface Animal .

Note: In Java, all the classes are inherited from the Object class. So, instances of all the classes are also an instance of the Object class.

In the previous example, if we check,

Источник

Пробуем улучшенный оператор instanceof в Java 14

Не за горами новая, 14-я версия Java, а значит самое время посмотреть, какие новые синтаксические возможности будет содержать эта версия Java. Одной из таких синтаксических возможностей является паттерн-матчинг по типу, который будет осуществляться посредством улучшенного (расширенного) оператора instanceof .

Читайте также:  Реализация логистической регрессии python

Сегодня я хотел бы поиграться с этим новым оператором и рассмотреть особенности его работы более детально. Так как паттерн-матчинг по типу ещё не вошёл в главный репозиторий JDK, мне пришлось скачать репозиторий проекта Amber, в котором ведётся разработка новых синтаксических конструкций Java, и собрать JDK из этого репозитория.

Итак, первое, что мы сделаем — проверим версию Java, чтобы убедиться, что мы действительно используем JDK 14:

> java -version openjdk version "14-internal" 2020-03-17 OpenJDK Runtime Environment (build 14-internal+0-adhoc.osboxes.amber-amber) OpenJDK 64-Bit Server VM (build 14-internal+0-adhoc.osboxes.amber-amber, mixed mode, sharing)

Теперь напишем небольшой кусок кода со «старым» оператором instanceof и запустим его:

public class A < public static void main(String[] args) < new A().f("Hello, world!"); >public void f(Object obj) < if (obj instanceof String) < String str = (String) obj; System.out.println(str.toLowerCase()); >> >

Работает. Это стандартная проверка на тип с последующим приведением. Подобные конструкции мы пишем изо дня в день, какую бы версию Java мы бы не использовали, хоть 1.0, хоть 13.
Но теперь у нас в руках Java 14, и давайте перепишем код с использованием улучшенного оператора instanceof (повторяющиеся строки кода в дальнейшем буду опускать):

if (obj instanceof String str)
> java --enable-preview --source 14 A.java hello, world!

Прекрасно. Код стал чище, короче, безопаснее и читабельнее. Было три повторения слова String, стало одно. Заметьте, что мы не забыли указать аргументы —enable-preview —source 14 , т.к. новый оператор является preview feature. Кроме того, внимательный читатель, наверное, заметил, что мы запустили исходный файл A.java напрямую, без компиляции. Такая возможность появилась в Java 11.

Давайте попробуем написать что-нибудь более навороченное и добавим второе условие, которое использует только что объявленную переменную:

if (obj instanceof String str && str.length() > 5)

Компилируется и работает. А что если поменять условия местами?

if (str.length() > 5 && obj instanceof String str)
A.java:7: error: cannot find symbol if (str.length() > 5 && obj instanceof String str) < ^

Ошибка компиляции. Чего и следовало ожидать: переменная str ещё не объявлена, а значит не может быть использована.

Кстати, что с мутабельностью? Переменная final или нет? Пробуем:

if (obj instanceof String str)
A.java:8: error: pattern binding str may not be assigned str = "World, hello!"; ^

Ага, переменная final. Это значит, что слово «переменная» здесь вообще не совсем корректно. Да и компилятор использует специальный термин «pattern binding». Поэтому предлагаю отныне говорить не «переменная», а «биндинг паттерна» (к сожалению, слово «binding» не очень хорошо переводится на русский).

С мутабельностью и терминологией разобрались. Поехали экспериментировать дальше. Вдруг у нас получится «сломать» компилятор?

Что если назвать переменную и биндинг паттерна одним и тем же именем?

if (obj instanceof String obj)
A.java:7: error: variable obj is already defined in method f(Object) if (obj instanceof String obj) < ^

Логично. Перекрытие переменной из внешней области видимости не работает. Это эквивалентно тому, как если бы мы просто завели переменную obj второй раз в той же области видимости.

if (obj instanceof String str && obj instanceof String str)
A.java:7: error: illegal attempt to redefine an existing match binding if (obj instanceof String str && obj instanceof String str) < ^

Компилятор надёжен как бетон.

Читайте также:  Java mobile application programing

Что ещё можно попробовать? Давайте поиграемся с областями видимости. Если в ветке if определён биндинг, то будет ли он определён в ветке else , если инвертировать условие?

if (!(obj instanceof String str)) < System.out.println("not a string"); >else

Сработало. Компилятор не только надёжен, но ещё и умён.

if (obj instanceof String str && true)

Опять сработало. Компилятор корректно понимает, что условие сводится к простому obj instanceof String str .

Неужели не удастся «сломать» компилятор?

if (obj instanceof String str || false)
A.java:8: error: cannot find symbol System.out.println(str.toLowerCase()); ^ 

Ага! Вот это уже похоже на баг. Ведь все три условия абсолютно эквивалентны:

  • obj instanceof String str
  • obj instanceof String str && true
  • obj instanceof String str || false

Но да ладно, давайте попробуем ещё что-нибудь. Будет ли работать такое:

if (!(obj instanceof String str)) < throw new RuntimeException(); >System.out.println(str.toLowerCase());
if (!(obj instanceof String str)) < throw new RuntimeException(); >else

А так как оба варианта эквивалентны, то и программист ожидает, что они будут работать одинаково.

Что насчёт перекрытия полей?

Компилятор не заругался. Это вполне логично, потому что локальные переменные всегда могли перекрывать поля. Для биндингов паттернов, видимо, тоже решили не делать исключения. С другой стороны, такой код довольно хрупок. Одно неосторожное движение, и вы можете не заметить, как ваша ветка if сломалась:

private boolean isOK() < return false; >public void f(Object obj) < if (obj instanceof String str || isOK()) < System.out.println(str.toLowerCase()); >else < System.out.println(str.toLowerCase()); >>

В обеих ветвях теперь используется поле str , чего может не ожидать невнимательный программист. Чтобы как можно раньше обнаруживать подобные ошибки, используйте инспекции в IDE и разную подсветку синтаксиса для полей и переменных. А ещё я рекомендую всегда использовать квалификатор this для полей. Это добавит ещё больше надёжности.

Что ещё интересного? Как и «старый» instanceof , новый никогда не матчит null . Это значит, что можно всегда полагаться на то, что биндинги паттернов никогда не могут быть null :

if (obj instanceof String str) < System.out.println(str.toLowerCase()); // Никогда не выбросит NullPointerException >

Кстати, используя это свойство, можно укоротить подобные цепочки:

Если использовать instanceof , то код выше можно переписать так:

if (a != null && a.getB() instanceof B b && b.getC() instanceof C c)

Напишите в комментариях, что вы думаете по поводу такого стиля. Стали ли бы вы использовать такую идиому?

import java.util.List; public class A < public static void main(String[] args) < new A().f(List.of(1, 2, 3)); >public void f(Object obj) < if (obj instanceof Listlist) < System.out.println(list.size()); >> >
> java --enable-preview --source 14 A.java Note: A.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. 3

Очень интересно. Если «старый» instanceof поддерживает только instanceof List или instanceof List , то новый работает с любым конкретным типом. Ждём первого человека, который попадётся вот в такую ловушку:

if (obj instanceof List list) < System.out.println("Int list of size " + list.size()); >else if (obj instanceof List list)

ИМХО, это довольно серьёзная проблема. С другой стороны, я не знаю, как можно было бы её исправить. Похоже, опять придётся полагаться на инспекции в IDE.

Выводы

В целом, новый паттерн-матчинг по типу работает очень круто. Улучшенный оператор instanceof позволяет делать не только тест на тип, но ещё и объявлять готовый биндинг этого типа, избавляя от необходимости ручного приведения. Это означает, что в коде будет меньше шума, и читателю будет гораздо проще разглядеть полезную логику. Например, большинство реализаций equals() можно будет писать в одну строчку:

public class Point < private final int x, y; … @Override public int hashCode() < return Objects.hash(x, y); >@Override public boolean equals(Object obj) < return obj instanceof Point p && p.x == this.x && p.y == this.y; >>

С другой стороны, вызывают небольшие вопросы несколько спорных моментов:

  • Не полностью прозрачные правила области видимости (пример с instanceof || false ).
  • Перекрытие полей.
  • instanceof и дженерики.
Читайте также:  Pandas python загрузка файла

P.S. У меня есть канал в Telegram, где я пишу о новостях Java. Призываю вас на него подписаться.

Источник

Java if instanceof string

Привет всем читающим 🙂 value это приватное статичное поле класса String, ей присвоено значение объекта String. String text = "123"; String text2 = "456"; text.equals(text2); // "123" это value

Про реализацию метода equals в классе String: Для пояснений можно взять следующий код: (можно в IDE его скопировать, чтоб посмотреть вывод)

 String first = "привет"; String linkToFirst = first; String second = new String ("привет"); System.out.println(first.equals(linkToFirst)); System.out.println(first.equals(second)); 

Первый System.out.println выведет true. И дойдет проверка только до первого if. Мы вызываем у объекта "first", типа String, метод equals, передавая в качестве параметра другую строку "linkToFirst", которая, как мы видим, просто ссылается на тот же самый объект. Оператор "this" ссылается на объект, который вызвал этот метод. В нашем случае - это "first" вызвал метод "equals", и в качестве передаваемого параметра отправил туда second. Когда мы написали в коде this, то подразумевали - "first". Т.е. Это можно прочитать как:

 public boolean equals(Object anObject) < if (first == second)  

Так почему же мы попадем только в первый if? Потому что при использовании оператора == при сравнении объектов, сравниваются не сами объекты, а только ссылки на них. А у нас как раз такая история - мы ссылаемся на один и тот же объект, получаем return true, и вывод в консоль true.

 public boolean equals(Object anObject)

Второй System.out.println выведет также true, но проверка уже пойдет по всему методу, ибо первый if выдаст false. Ведь second не ссылается на first привет, а ссылается на новый объект

 if (anObject instanceof String) < //Проверяем, является ли строкой, // переданный в метод объект (second) String anotherString = (String) anObject; //если да, то приводим // переданный объект к типу String int n = value.length; // value - это массив символов*, объекта String, // который вызывает метод equals. // value.length - его длина. *- на самом деле это массив байтов, и каждый // символ может быть представлен в виде 1, 2, 3 или даже 4 байтами, // но сути это не меняет if (n == anotherString.value.length) < // сравниваем длину массива // символов текущего объекта, с переданным т.е. длину first и second) char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) < // далее мы в цикле уменьшаем количество // заходов в while и поочередно сравниваем между собой элементы (символы) // массивов исходного "first " и переданного // "second" (берется один и тот же индекс массива - "i"). // Как только они не совпадут - false и выход из цикла. // Если цикл завершился без преждевременного окончания, // значит объекты идентичны. if (v1[i] != v2[i]) return false; i++; > return true; > > return false; 

Источник

Оцените статью