Java использует объект Class
для реализации собственной функциональности RTTI — даже если мы выполняем простую работу, такую как преобразование типов. Класс Class
также предоставляет множество других способов, чтобы сделать использование RTTI более удобным.
Сначала необходимо получить ссылку на подходящий объект Class
. Как показано в предыдущих примерах, один из методов заключается в использовании строки вместе с методом Class.forName()
. Это очень удобно, поскольку не требуется объект данного типа для получения ссылки на Class
. Однако, если уже имеется объект интересующего нас типа, можно вызвать метод getClass()
, который является частью базового класса Object
. Этот метод возвращает специфическую ссылку на Class
, которая представляет собой фактический тип объекта. Класс Class
предлагает несколько интересных и полезных методов, что видно из следующего примера:
//: ToyTest.java
// Тестирование класса Class
interface HasBatteries {}
interface Waterproof {}
interface ShootsThings {}
class Toy {
// Удалите следующий по умолчанию конструктор, чтобы увидеть
// NoSuchMethodError от (*1*)
Toy() {}
Toy(int i) {}
}
class FancyToy extends Toy
implements HasBatteries,
Waterproof, ShootsThings {
FancyToy() { super(1); }
}
``````java
public class ToyTest {
public static void main(String[] args) {
Class<?> c = null;
try {
c = Class.forName("FancyToy");
} catch(ClassNotFoundException e) {}
printInfo(c);
Class<?>[] faces = c.getInterfaces();
for(int i = 0; i < faces.length; i++) {
printInfo(faces[i]);
}
Class<?> cy = c.getSuperclass();
Object o = null;
try {
// Requires a default constructor:
o = cy.newInstance(); // (*1*)
} catch(InstantiationException e) {}
catch(IllegalAccessException e) {}
printInfo(o.getClass());
}
}
Здесь текст внутри комментария был переведён:
// Требуется конструктор по умолчанию:
на
// Requires a default constructor:````markdown В этом примере класс
FancyToyдовольно сложен, так как он наследует от класса
Toyи реализует интерфейсы
HasBatteries,
Waterproofи
ShootsThings. В методе
main()создается ссылка на класс
Class, которая затем инициализируется значением
FancyToyвнутри соответствующего блока
try`.
Метод getInterfaces()
класса Class
возвращает массив объектов Class
, представляющих интерфейсы, содержащиеся в данном объекте Class
. Если имеется объект типа Class
, можно использовать метод getSuperclass()
, чтобы получить прямого родителя этого объекта. Этот метод вернет ссылку типа Class
, которую можно использовать для дальнейших запросов. Это означает, что во время выполнения программы есть возможность полностью исследовать иерархию наследования объекта.
```На первый взгляд может показаться, что метод newInstance()
класса `Class` является альтернативой методу клонирования (`clone()`). Однако эти два подхода имеют различия. Используя `newInstance()`, мы можем создать новый объект даже в том случае, если нет существующего объекта для "клонирования". Как демонстрируется в примере выше, когда нет объекта типа `Toy`, имеется ссылка на объект типа `Class`, который представляет класс `Toy`. Эта ссылка позволяет нам создать "виртуальный конструктор", то есть сказать: "Независимо от того, какой именно тип ты представляешь, пожалуйста, создай себя правильно." В данном контексте ссылка `cy` является просто ссылкой на объект типа `Class`, и компилятор не имеет информации о конкретном типе до создания нового экземпляра. После создания нового экземпляра получаем ссылку типа `Object`, но она указывает на объект типа `Toy`. Для отправки сообщений, кроме тех, которые могут принимать объекты типа `Object`, потребуется дополнительное преобразование. Кроме того, класс, созданный с помощью `newInstance()`, должен иметь конструктор по умолчанию. Создание объектов с использованием других конструкторов через `newInstance()` невозможно, поэтому в Java 1.0 могли возникнуть ограничения. Тем не менее, API "рефлексии" в Java 1.1 (обсуждается в следующем разделе) позволяет нам динамически использовать любой конструктор внутри класса.Последний метод в программе — это `printInfo()`, который принимает ссылку на объект типа `Class`, использует метод `getName()` для получения имени класса и метод `isInterface()` для проверки, является ли данный класс интерфейсом.
Выходные данные программы следующие:
Имя класса: FancyToy - является интерфейсом? [false]
Имя класса: HasBatteries - является интерфейсом? [true]
Имя класса: Waterproof - является интерфейсом? [true]
Имя класса: ShootsThings - является интерфейсом? [true]
Имя класса: Toy - является интерфейсом? [false]
С помощью объекта типа Class
можно практически полностью исследовать иерархию наследования объекта.
Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Опубликовать ( 0 )