Перейти к основному содержимому

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

· 5 мин. чтения

1. Обзор

В 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 .