Як визначити клас об’єкта?


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))
Dzhuneyt

32
Я вважаю, що метод getClass () - це відповідь на початкове запитання. У цьому випадку (obj instanceof A) також дасть "істинний" висновок, але намір полягає в тому, щоб знайти клас виконання об'єкта на зображенні. Якщо Parent1 подовжено на Child1 та Child2, спробуйте наступне code Child1 child1 = new Child1 (); Parent1 parentChild = новий Child2 (); Child2 child2 = новий 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

бездоганна відповідь @Bill
gaurav

1
Не впевнений, чому це не найпопулярніша відповідь
eicksl

178

Було представлено кілька правильних відповідей, але є ще методи: Class.isAssignableFrom()і спроба кинути об'єкт (що може кинути а 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поводженні, хоча:

  • У перших двох методах вирази оцінюють, falseякщо objє null( nullне є примірником нічого).
  • 3-й метод кинув би NullPointerExceptionочевидно.
  • 4-й і 5-й методи навпаки приймають, nullтому що nullможуть бути передані будь-якому типу!

Пам'ятайте: null це не примірник будь-якого типу, але його можна передавати будь-якому типу.

Примітки

  • Class.getName()не повинен використовуватися для виконання тестового вікна "є екземпляр", якщо об'єкт не типу, 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

HTH. Але я думаю, що в більшості випадків це не належна практика використовувати це для контролю потоку або щось подібне ...


Я використовував його для створення загального реєстратора, тому я надіслав об’єкт до реєстратора, і він записує журнал залежно від назви класу об'єкта, а не давати тег журналу або рядок журналу кожного разу. дякую
MBH

24

Будь-яке використання будь-якого із запропонованих методів вважається кодовим запахом, який базується на поганому дизайні ОО.

Якщо ваш дизайн хороший, ви не повинні вважати себе необхідним використовувати getClass()або instanceof.

Будь-який із запропонованих методів буде зроблений, але лише щось, про що слід пам’ятати, розробити дизайн.


3
Так, ймовірно, 99% використання getClass та instanceof можна уникнути за допомогою викликів поліморфних методів.
Білл Ящірка

3
я згоден. У цьому випадку я працюю з об’єктами, згенерованими з xml, за погано розробленою схемою, на яку я не маю права власності.
перевізник

28
Не неодмінно. Іноді розділення інтерфейсів добре. Бувають випадки, коли ви хочете дізнатися, чи є A B, але ви не хочете, щоб це було обов'язковим, що A є B, оскільки для більшості функціональних можливостей потрібен лише A - B має додатковий функціонал.
MetroidFan2002

8
Також бувають випадки, коли вам потрібно переконатися, що об’єкт того самого класу, з яким ви порівнюєте; наприклад, мені подобається переосмислювати метод рівних Object, коли я створюю власний клас. Я завжди переконуюсь, що об'єкт, що надходить, є одного класу.
StackOverflowed

58
Крім того, я б сказав, що говорити людям щось погано, не пояснюючи, чому саме та не посилаючись на папір, книгу чи будь-який інший ресурс, де пояснюється питання, вважається неконструктивним. Тому, знаючи, що я перебуваю в StackOverflow, я не знаю, чому люди так сильно підтримали цю відповідь. Тут щось змінюється ...
Адріан Перес

15

Ми можемо використовувати рефлексію в цьому випадку

objectName.getClass().getName();

Приклад: -

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

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

У цьому випадку ви отримаєте ім'я класу, який об'єкт переходить до HttpServletRequestзмінної інтерфейсу.


це вірно. з використанням лише obj.getClass()поверне класName, префікс словомclass
x6iae

request.getClass().getName();роздруковує весь пакет! разом із назвою класу
shareef

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.