Как определить класс объекта?


510

Если класс Bи класс Cрасширяют класс, Aи у меня есть объект типа Bили C, как я могу определить, к какому типу он относится?


14
@starblue Кастинг будет первым, что приходит на ум. Я сомневаюсь, что оператор instanceof существовал бы, если бы в этом не было необходимости.
b1nary.atr0phy

@ b1nary.atr0phy было бы неплохо сначала использовать оператор isntanceof. Если есть приведение к несовместимому типу, я считаю , что приведет к ClassCastException
committedandroider

Ответы:


801
if (obj instanceof C) {
//your code
}

31
Полезно отметить обратную проверку или как проверить, не является ли объект НЕ экземпляром класса:if(!(obj instanceof C))
Джунейт

32
Я считаю, что метод getClass () является ответом на оригинальный вопрос. В этом случае (obj instanceof A) также даст «истинный» вывод, но цель состоит в том, чтобы найти класс времени выполнения объекта на рисунке. Если Parent1 расширен на Child1 и Child2, попробуйте следующее code Child1 child1 = new Child1 (); Parent1 parentChild = new Child2 (); Child2 child2 = new Child2 (); (child1 instanceof Parent1); (child1 instanceof Child1); (parentChild instanceof Child2); (parentChild instanceof Parent1); (parentChild instanceof Child1); code , это может очистить намерение instanceof.
Бхавеш Агарвал

Определенно альтернатива созданию интерфейса
JohnMerlino

3
Что если у меня есть два класса, реализующих один интерфейс? Как определить точный класс объекта?
Олив

3
Одна вещь, хотя, это не работает, если obj является нулем. Тогда решением будет ParentInterface.class.isAssignableFrom (Child.class)
alexbt

351

Используйте Object.getClass () . Возвращает тип времени выполнения объекта.


12
Это на самом деле, как вы определяете класс объекта
AA_PV

безупречный ответ @ Билл
Гаурав

1
Не уверен, почему это не самый популярный ответ
eicksl

178

Было представлено несколько правильных ответов, но есть еще несколько методов: Class.isAssignableFrom()и просто попытка привести объект (который может вызвать a ClassCastException).

Возможные пути обобщены

Давайте суммируем возможные способы проверить, является ли объект objэкземпляром типа C:

// Method #1
if (obj instanceof C)
    ;

// Method #2
if (C.class.isInstance(obj))
    ;

// Method #3
if (C.class.isAssignableFrom(obj.getClass()))
    ;

// Method #4
try {
    C c = (C) obj;
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

// Method #5
try {
    C c = C.class.cast(obj);
    // No exception: obj is of type C or IT MIGHT BE NULL!
} catch (ClassCastException e) {
}

Отличия в nullобработке

Есть разница в nullобработке, хотя:

  • В первых двух методах выражения оцениваются как falseif objis null( nullне является экземпляром чего-либо).
  • Третий метод бросил бы NullPointerExceptionочевидно.
  • 4-й и 5-й методы наоборот принимают, nullпотому что nullмогут быть приведены к любому типу!

Помнить: null это не экземпляр любого типа, но он может быть приведен к любому типу.

Ноты

  • Class.getName()не должен использоваться для выполнения теста "is-instance-of", если объект не типа, Cа подкласса, он может иметь совершенно другое имя и пакет (поэтому имена классов, очевидно, не будут совпадать), но это все еще типа C.
  • По той же причине наследования Class.isAssignableFrom()не является симметричным :
    obj.getClass().isAssignableFrom(C.class)будет возвращать, falseесли тип objявляется подклассом C.

6
Это действительно большое резюме многих подводных камней в различных методах. Спасибо за такую ​​полную запись!
Келсин

32

Ты можешь использовать:

Object instance = new SomeClass();
instance.getClass().getName(); //will return the name (as String) (== "SomeClass")
instance.getClass(); //will return the SomeClass' Class object

НТН. Но я думаю, что в большинстве случаев не рекомендуется использовать это для управления потоком данных или чего-то подобного ...


Я использовал его для создания универсального регистратора, поэтому я отправил объект в регистратор, и он записывает в журнал в зависимости от имени класса объекта, вместо того, чтобы каждый раз указывать тег журнала или строку журнала. спасибо
MBH

24

Любое использование любого из предложенных методов считается запахом кода, который основан на плохом дизайне ОО.

Если ваш дизайн хороший, вам не нужно использовать getClass()или instanceof.

Подойдет любой из предложенных методов, но только то, что нужно иметь в виду, с точки зрения дизайна.


3
Да, возможно, 99% использования getClass и instanceof можно избежать с помощью полиморфных вызовов методов.
Билл Ящерица

3
я согласен в этом случае я работаю с объектами, сгенерированными из xml по плохо разработанной схеме, владельцем которой я не являюсь.
перевозчик

28
Не обязательно. Иногда разделение интерфейсов это хорошо. Есть моменты, когда вы хотите знать, является ли A буквой B, но вы не хотите делать обязательным, чтобы A был буквой B, поскольку для большинства функций требуется только A - B имеет дополнительные функции.
MetroidFan2002

8
Кроме того, бывают случаи, когда вам нужно убедиться, что объект относится к тому же классу, с которым вы сравниваете; например, мне нравится переопределять метод equals объекта, когда я создаю свой собственный класс. Я всегда проверяю, входит ли объект в тот же класс.
Переполнение стека

58
Кроме того, я бы сказал, что рассказывать людям что-то плохое, не объясняя точно, почему и не давая ссылки на статью, книгу или любой другой ресурс, где объясняется проблема, считается неконструктивным. Поэтому, зная, что я нахожусь в StackOverflow, я не знаю, почему люди так проголосовали за этот ответ. Здесь что-то меняется ...
Адриан Перес

15

Мы можем использовать отражение в этом случае

objectName.getClass().getName();

Пример:-

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    String name = request.getClass().getName();
}

В этом случае вы получите имя класса, объект которого передается в HttpServletRequestинтерфейсную переменную.


это правильно. использование only obj.getClass()вернет className, prefixex по словуclass
x6iae

request.getClass().getName();печатает всю упаковку! вместе с именем класса
Шариф

13

Существует также .isInstanceметод Classкласса " ". если вы получаете класс объекта через, myBanana.getClass()вы можете увидеть, является ли ваш объект myAppleэкземпляром того же класса, что и myBananaчерез

myBanana.getClass().isInstance(myApple)

1

Проверка с помощью isinstance()будет недостаточно, если вы хотите знать во время выполнения. использовать:

if(someObject.getClass().equals(C.class){
    // do something
}

0

Я использую функцию удара в своем классе GeneralUtils, проверьте, может быть полезно

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}

0

Я использовал дженерики Java 8, чтобы получить экземпляр объекта во время выполнения, а не использовать регистр

 public <T> void print(T data) {
    System.out.println(data.getClass().getName()+" => The data is " + data);
}

Передайте любой тип данных, и метод напечатает тип данных, которые вы передали при его вызове. например

    String str = "Hello World";
    int number = 10;
    double decimal = 10.0;
    float f = 10F;
    long l = 10L;
    List list = new ArrayList();
    print(str);
    print(number);
    print(decimal);
    print(f);
    print(l);
    print(list);

Ниже приведен вывод

java.lang.String => The data is Hello World
java.lang.Integer => The data is 10
java.lang.Double => The data is 10.0
java.lang.Float => The data is 10.0
java.lang.Long => The data is 10
java.util.ArrayList => The data is []
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.