Как определить класс объекта?
У меня есть два класса: B
и C
, которые наследуются от класса A
. Теперь у меня есть объект, который является экземпляром одного из этих классов — B
или C
. Как можно определить, к какому именно типу относится этот объект? Есть ли способ сделать это в языке программирования, который я использую?
5 ответ(ов)
Если объект obj
является экземпляром класса C
, то выполните следующий код:
if (obj instanceof C) {
// ваш код
}
Несколько правильных ответов были представлены, но существуют и другие методы: Class.isAssignableFrom()
и простой попытки привести объект к нужному типу (что может вызвать ClassCastException
).
Резюме возможных способов
Давайте подытожим возможные способы проверки, является ли объект obj
экземпляром типа C
:
// Метод #1
if (obj instanceof C)
;
// Метод #2
if (C.class.isInstance(obj))
;
// Метод #3
if (C.class.isAssignableFrom(obj.getClass()))
;
// Метод #4
try {
C c = (C) obj;
// Если исключения нет: obj имеет тип C или он может быть NULL!
} catch (ClassCastException e) {
}
// Метод #5
try {
C c = C.class.cast(obj);
// Если исключения нет: obj имеет тип C или он может быть NULL!
} catch (ClassCastException e) {
}
Различия в обработке null
Существует различие в обработке null
:
- В первых двух методах выражения возвращают
false
, еслиobj
равноnull
(то естьnull
не является экземпляром чего-либо). - Третий метод приведет к
NullPointerException
, еслиobj
равноnull
. - Напротив, четвертый и пятый методы принимают
null
, так какnull
может быть приведен к любому типу!
Напомним:
null
не является экземпляром какого-либо типа, но его можно привести к любому типу.
Замечания
Class.getName()
не следует использовать для выполнения теста на "является ли экземпляром" потому что, если объект не является типомC
, а подклассом этого типа, он может иметь совершенно другое имя и пакет (поэтому имена классов, очевидно, не совпадут), но при этом он все еще будет считаться типомC
.- По той же причине наследования
Class.isAssignableFrom()
не является сymmetric:
obj.getClass().isAssignableFrom(C.class)
вернет false
, если тип obj
является подклассом C
.
Вы можете использовать:
Object instance = new SomeClass();
instance.getClass().getName(); // вернет имя класса (в виде строки) (== "SomeClass")
instance.getClass(); // вернет объект класса SomeClass
Надеюсь, это поможет. Однако я думаю, что чаще всего не является хорошей практикой использовать это для управления потоком или что-то подобное...
Использование любых из предложенных методов считается "ароматом кода", что указывает на плохой объектно-ориентированный дизайн.
Если ваш дизайн хорош, вам не потребуется использовать getClass()
или instanceof
.
Любой из предложенных методов вполне сгодится, но это стоит учитывать с точки зрения дизайна.
В данном случае мы можем использовать рефлексию для получения имени класса объекта.
Пример кода:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String name = request.getClass().getName();
}
В результате выполнения этого кода вы получите имя класса объекта, который передается в переменную-ссылку HttpServletRequest
. Это может быть полезно для отладки или логирования, чтобы узнать, какой именно класс был использован в данном контексте.
Является ли List<Собака> подклассом List<Животное>? Почему дженерики в Java не являются неявно полиморфными?
Как мне следовало объяснить разницу между интерфейсом и абстрактным классом? [закрыто]
Как объявить массив в одну строку?
Загрузка JDK Java на Linux через wget приводит к отображению страницы лицензии вместо установки
Создание репозитория Spring без сущности