Как определить класс объекта?
У меня есть два класса: 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 не являются неявно полиморфными?
Как мне следовало объяснить разницу между интерфейсом и абстрактным классом? [закрыто]
Что значит 'synchronized'?
Как объявить массив в одну строку?
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?