Getclass java что это
Перейти к содержимому

Getclass java что это

  • автор:

Разница между a.getClass() и A.class в Java

В Java класс java.lang.Class является точкой входа для всех операций отражения . Когда у нас есть объект java.lang.Class , мы можем вызывать соответствующие методы для получения объектов классов отражения.

В этом руководстве мы обсудим различия между двумя разными способами получения объекта java.lang.Class :

  • Вызов метода Object.getClass()
  • Использование синтаксиса .class

2. Краткое введение в два подхода​

Метод Object.getClass() является методом экземпляра класса Object . Если у нас есть объект, мы можем вызвать object.getClass() , чтобы получить объект Class его типа.

Точно так же мы можем использовать синтаксис ClassName.class , чтобы получить объект Class типа. Пример может объяснить это ясно:

 @Test   public void givenObjectAndType_whenGettingClassObject_thenTwoMethodsHaveTheSameResult()    String str = "I am an object of the String class";    Class fromStrObject = str.getClass();   Class clazz = String.class;    assertSame(fromStrObject, clazz);   > 

В приведенном выше тестовом методе мы пытаемся получить объект Class класса String , используя два упомянутых нами способа. Наконец, метод утверждения сообщает нам, что два объекта класса являются одним и тем же экземпляром.

Однако между этими двумя подходами есть различия. Давайте рассмотрим их поближе.

3. Тип времени выполнения против статического типа​

Давайте быстро рассмотрим предыдущий пример. Когда мы вызываем метод str.getClass() , мы получаем тип объекта str во время выполнения . С другой стороны, String.class оценивает класс String статически . В этом примере тип времени выполнения str и String.class совпадают.

Однако они могут быть и другими, если к партии присоединится наследование классов. Давайте посмотрим на два простых класса:

 public class Animal    protected int numberOfEyes;   >    public class Monkey extends Animal    // monkey stuff   > 

Теперь давайте создадим объект класса Animal и проведем еще один тест:

 @Test   public void givenClassInheritance_whenGettingRuntimeTypeAndStaticType_thenGetDifferentResult()    Animal animal = new Monkey();    Class runtimeType = animal.getClass();   Class staticType = Animal.class;    assertSame(staticType, runtimeType);   > 

Если мы запустим тест выше, мы получим отказ теста:

 java.lang.AssertionError: ....  Expected :class com.foreach.getclassobject.Animal Actual :class com.foreach.getclassobject.Monkey 

В тестовом методе, даже если мы создали объект животного с помощью Animal animal = new Monkey(); вместо Monkey animal = new Monkey(); , тип объекта животного во время выполнения по- прежнему Monkey. Это связано с тем, что объект животного является экземпляром Monkey во время выполнения.

Однако когда мы получаем статический тип класса Animal , это всегда тип Animal .

4. Работа с примитивными типами​

Когда мы пишем код на Java, мы довольно часто используем примитивные типы. Попробуем получить объект Class примитивного типа, используя подход object.getClass() :

 int number = 7;   Class numberClass = number.getClass(); 

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

 Error: java: int cannot be dereferenced 

Компилятор не может разыменовать числовую переменную , поскольку это примитивная переменная. Поэтому метод object.getClass() не может помочь нам получить объект Class примитивного типа.

Давайте посмотрим, сможем ли мы получить примитивный тип, используя синтаксис .class :

 @Test   public void givenPrimitiveType_whenGettingClassObject_thenOnlyStaticTypeWorks()    Class intType = int.class;   assertNotNull(intType);   assertEquals("int", intType.getName());   assertTrue(intType.isPrimitive());   > 

Итак, мы можем получить объект Class примитивного типа int через int.class . В Java версии 9 и более поздних версиях объект Class примитивного типа принадлежит модулю java.base .

Как показывает тест, синтаксис .class — это простой способ получить объект Class примитивного типа.

5. Получение класса без экземпляра​

Мы узнали, что метод object.getClass() может дать нам объект класса его типа во время выполнения .

Теперь давайте рассмотрим случай, когда мы хотим получить объект Class типа, но мы не можем получить экземпляр целевого типа, потому что это абстрактный класс, интерфейс или какой-то класс не допускает создание экземпляров:

 public abstract class SomeAbstractClass    // .   >    interface SomeInterface    // some methods .   >    public class SomeUtils    private SomeUtils()    throw new RuntimeException("This Util class is not allowed to be instantiated!");   >   // some public static methods.   > 

В этих случаях мы не можем получить объекты класса этих типов с помощью метода object.getClass() , но мы все равно можем использовать синтаксис .class для получения их объектов класса :

 @Test   public void givenTypeCannotInstantiate_whenGetTypeStatically_thenGetTypesSuccefully()    Class interfaceType = SomeInterface.class;   Class abstractClassType = SomeAbstractClass.class;   Class utilClassType = SomeUtils.class;    assertNotNull(interfaceType);   assertTrue(interfaceType.isInterface());   assertEquals("SomeInterface", interfaceType.getSimpleName());    assertNotNull(abstractClassType);   assertEquals("SomeAbstractClass", abstractClassType.getSimpleName());    assertNotNull(utilClassType);   assertEquals("SomeUtils", utilClassType.getSimpleName());   > 

Как показывает приведенный выше тест, синтаксис .class может получать объекты класса для этих типов.

Поэтому, когда мы хотим иметь объект класса , но не можем получить экземпляр типа, лучше всего использовать синтаксис .class .

6. Заключение​

В этой статье мы узнали о двух разных способах получения объекта Class типа: метод object.getClass() и синтаксис .class .

Позже мы обсудили разницу между этими двумя подходами. Следующая таблица может дать нам четкое представление:

 | | `объект.получитькласс()` | `SomeClass.класс` |  | **Объекты класса** | Тип `объекта во время выполнения` | Статический тип `SomeClass` |  | **Примитивные типы** | — | Работает прямо |  | **Интерфейсы, абстрактные классы или классы, которые не могут быть созданы** | — | Работает прямо | 

Как всегда, полный исходный код статьи доступен на GitHub .

Как узнать класс объекта java

Чтобы узнать класс объекта в Java, можно использовать метод getClass() :

Object obj = new String("Hello, World!"); Class cls = obj.getClass(); System.out.println("Class of obj: " + cls.getName()); 

В этом примере мы создаем объект String , затем вызываем метод getClass() , чтобы получить класс этого объекта, и, наконец, используем метод getName() , чтобы получить имя класса. Результатом будет:

Class of obj: java.lang.String 

Метод getClass() возвращает объект типа Class , который содержит информацию о классе объекта. Мы можем использовать этот объект для получения информации о классе, такой как имя, модификаторы доступа, поля, методы и т.д.

Getclass java что это

Хотя мы можем создать обычный класс, который не является наследником, но фактически все классы наследуются от класса Object. Все остальные классы, даже те, которые мы добавляем в свой проект, являются неявно производными от класса Object. Поэтому все типы и классы могут реализовать те методы, которые определены в классе Object. Рассмотрим эти методы.

toString

Метод toString служит для получения представления данного объекта в виде строки. При попытке вывести строковое представления какого-нибудь объекта, как правило, будет выводиться полное имя класса. Например:

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); System.out.println(tom.toString()); // Будет выводить что-то наподобие Person@7960847b >> class Person < private String name; public Person(String name)< this.name=name; >>

Полученное мной значение (в данном случае Person@7960847b ) вряд ли может служить хорошим строковым описанием объекта. Поэтому метод toString() нередко переопределяют. Например:

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); System.out.println(tom.toString()); // Person Tom >> class Person < private String name; public Person(String name)< this.name=name; >@Override public String toString() < return "Person " + name; >>

Метод hashCode

Метод hashCode позволяет задать некоторое числовое значение, которое будет соответствовать данному объекту или его хэш-код. По данному числу, например, можно сравнивать объекты.

Например, выведем представление вышеопределенного объекта:

Person tom = new Person("Tom"); System.out.println(tom.hashCode()); // 2036368507

Но мы можем задать свой алгоритм определения хэш-кода объекта:

class Person < private String name; public Person(String name)< this.name=name; >@Override public int hashCode() < return 10 * name.hashCode() + 20456; >>

Получение типа объекта и метод getClass

Метод getClass позволяет получить тип данного объекта:

Person tom = new Person("Tom"); System.out.println(tom.getClass()); // class Person

Метод equals

Метод equals сравнивает два объекта на равенство:

public class Program < public static void main(String[] args) < Person tom = new Person("Tom"); Person bob = new Person("Bob"); System.out.println(tom.equals(bob)); // false Person tom2 = new Person("Tom"); System.out.println(tom.equals(tom2)); // true >> class Person < private String name; public Person(String name)< this.name=name; >@Override public boolean equals(Object obj) < if (!(obj instanceof Person)) return false; Person p = (Person)obj; return this.name.equals(p.name); >>

Метод equals принимает в качестве параметра объект любого типа, который мы затем приводим к текущему, если они являются объектами одного класса.

Оператор instanceof позволяет выяснить, является ли переданный в качестве параметра объект объектом определенного класса, в данном случае класса Person. Если объекты принадлежат к разным классам, то их сравнение не имеет смысла, и возвращается значение false.

Затем сравниваем по именам. Если они совпадают, возвращаем true, что будет говорить, что объекты равны.

Java getClass или instanceof для equals

Что лучше использовать для сравнения типов классов у переменных при написании equals ? Я уже описывал этот метод в специальной статье. С одной стороны, я часто видел использование instanceof :

class MyObject < private String field ; public String getField ( ) < return field ; public void setField ( String field ) < this . field = field ; public boolean equals ( final Object other ) < if ( ! ( other instanceof MyObject ) ) < return false ; MyObject castOther = ( MyObject ) other ; return Objects . equals ( field , castOther . field ) ; public int hashCode ( ) < return Objects . hash ( field ) ;

На первый взгляд, здесь всё впорядке. Но давайте создадим дочерний класс:

class MyChildObject extends MyObject < private boolean v1 ; public boolean isV1 ( ) < public void setV1 ( boolean v1 ) < this . v1 = v1 ; public boolean equals ( final Object other ) < if ( ! ( other instanceof MyChildObject ) ) < return false ; MyChildObject castOther = ( MyChildObject ) other ; return Objects . equals ( v1 , castOther . v1 ) ; public int hashCode ( ) < return Objects . hash ( v1 ) ;

Вроде тоже ничего плохого. Но давайте проведём следующий эксперимент:

my.equals(child) = true
child.equals(my) = false

Но в договорённости о работе equals в официальном JavaDoc сказано, что метод должен быть симметричным. Симметричность означает, что для каждой пары x и y у которой x . equals ( y ) должно быть равно y . equals ( x ) . Значит, наши методы некорректны. Перепишем их на getClass :

class MyObject < public boolean equals ( final Object other ) < if ( other == null ) < return false ; if ( ! getClass ( ) . equals ( other . getClass ( ) ) ) < return false ; MyObject castOther = ( MyObject ) other ; return Objects . equals ( field , castOther . field ) ; class MyChildObject < public boolean equals ( final Object other ) < if ( other == null ) < return false ; if ( ! getClass ( ) . equals ( other . getClass ( ) ) ) < return false ; MyChildObject castOther = ( MyChildObject ) other ; return Objects . equals ( v1 , castOther . v1 ) ; public int hashCode ( ) < return Objects . hash ( v1 ) ;

Проведём эксперимент ещё раз:

my.equals(child) = false
child.equals(my) = false

Теперь класс может быть равен другому классу только если он строго того же типа, что и второй класс. Зато выполняется правило рефлексии для equals .

Вывод: Для equals всегда нужно сравнивать типы объектов через getClass.

Все методы equals и hashCode для данной статьи были сгенерированы с помощью плагина Jenerate для Eclipse.

Опубликовано 05.08.2019 05.08.2019 Автор Урванов Фёдор Рубрики Java Метки Java

Java getClass или instanceof для equals: 3 комментария

Аноним :
equals не всегда симметричен.
в той же HashMap это не так.
Аноним :

А что, если наш объект — энтити хибернейт? getClass у такого объекта укажет нам на прокси и мы не сможем добраться до сравнения полей объекта.

Урванов Фёдор :

Ну да, возможно, для Hibernate это не всегда подходит, хотя и тоже спорно. Но требование по симметричности вообще было в самой документации от Oracle, поэтому я его здесь привёл.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *