Jak określić klasę obiektu?

510

Jeśli klasa Bi klasa Crozszerzają klasę, Aa ja mam obiekt typu Blub C, jak mogę ustalić, który typ jest instancją?

nośnik
źródło
14
@starblue Casting będzie pierwszą rzeczą, jaka przychodzi na myśl. Wątpię, by instancja operatora istniałaby, gdyby nie było takiej potrzeby.
b1nary.atr0phy
@ b1nary.atr0phy nie byłoby dobrze, aby najpierw użyć operatora isntanceof. Jeśli istnieje oddanych do niezgodnego typu, wierzę, że spowoduje ClassCastException
committedandroider

Odpowiedzi:

801
if (obj instanceof C) {
//your code
}
IAdapter
źródło
31
Przydatne jest zwrócenie uwagi na sprawdzenie wsteczne lub sprawdzenie, czy Obiekt NIE jest instancją klasy:if(!(obj instanceof C))
Dzhuneyt,
32
Wierzę, że metoda getClass () jest odpowiedzią na pierwotne pytanie. W tym przypadku (obj instanceof A) również dałby wynik „true”, ale celem jest znalezienie klasy środowiska wykonawczego obiektu na obrazie. Jeśli Parent1 jest przedłużony przez Child1 i Child2, spróbuj następujących Child1 child1 code = 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 , może wyczyścić zamiar instanceof.
Bhavesh Agarwal
Zdecydowanie alternatywa dla budowy interfejsu
JohnMerlino,
3
Co jeśli mam dwie klasy implementujące pojedynczy interfejs? Jak odróżnić dokładną klasę obiektu?
olyv
3
Jedną rzeczą jest to, że nie działa, jeśli obj ma wartość null. Rozwiązaniem byłby wtedy ParentInterface.class.isAssignableFrom (Child.class)
alexbt
351

Użyj Object.getClass () . Zwraca typ środowiska wykonawczego obiektu.

Bill jaszczurka
źródło
12
Tak właśnie
określasz
bezbłędna odpowiedź @Bill
gaurav
1
Nie jestem pewien, dlaczego nie jest to najpopularniejsza odpowiedź
eicksl
178

Przedstawiono wiele poprawnych odpowiedzi, ale jest jeszcze więcej metod: Class.isAssignableFrom()i po prostu próba rzucenia obiektu (co może rzucić a ClassCastException).

Możliwe sposoby podsumowane

Podsumujmy możliwe sposoby sprawdzenia, czy obiekt objjest instancją typu 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) {
}

Różnice w nullobsłudze

Jest jednak różnica w nullobsłudze:

  • W pierwszych 2 metodach wyrażenia oceniają, falseczy objjest null( nullnie jest instancją czegokolwiek).
  • Trzecia metoda rzuciłaby NullPointerExceptionoczywiście.
  • Czwarta i piąta metoda wręcz przeciwnie akceptują, nullponieważ nullmożna je zastosować do dowolnego typu!

Pamiętaj: null nie jest instancją żadnego typu, ale można ją rzutować na dowolny typ.

Notatki

  • Class.getName()nie powinien być używany do wykonywania testu „jest-wystąpieniem-z”, ponieważ jeśli obiekt nie jest typu, Cale jego podklasą, może mieć zupełnie inną nazwę i pakiet (dlatego nazwy klas oczywiście nie będą pasować), ale jest nadal typu C.
  • Z tego samego powodu dziedziczenia Class.isAssignableFrom()nie jest symetryczny :
    obj.getClass().isAssignableFrom(C.class)zwróci, falsejeśli typ objjest podklasą C.
icza
źródło
6
To naprawdę świetne podsumowanie wielu pułapek różnych metod. Dzięki za tak kompletne napisanie!
Kelsin,
32

Możesz użyć:

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

HTH. Ale myślę, że przez większość czasu nie jest dobrą praktyką stosowanie tego do kontroli przepływu lub coś podobnego ...

Johannes Weiss
źródło
Użyłem go do stworzenia ogólnego loggera, więc wysłałem obiekt do loggera, i loguje się on w zależności od nazwy klasy obiektu, zamiast za każdym razem podawać tag log lub ciąg logu. dziękuję
MBH
24

Każde użycie którejkolwiek z sugerowanych metod jest uważane za zapach kodu, który opiera się na złym projekcie OO.

Jeśli twój projekt jest dobry, nie powinieneś potrzebować używania getClass()lub instanceof.

Każda z sugerowanych metod zadziała, ale tylko coś, o czym należy pamiętać, jeśli chodzi o projekt.

Yuval Adam
źródło
3
Tak, prawdopodobnie można uniknąć 99% zastosowań getClass i instanceof przy użyciu polimorficznych wywołań metod.
Bill the Jaszczurka
3
Zgadzam się. w tym przypadku pracuję z obiektami wygenerowanymi z xml według źle zaprojektowanego schematu, do którego nie mam prawa własności.
przewoźnik
28
Nie koniecznie. Czasami separacja interfejsów jest dobra. Są chwile, gdy chcesz wiedzieć, czy A jest B, ale nie chcesz, aby A było obowiązkowe, ponieważ tylko A jest wymagane dla większości funkcji - B ma funkcjonalność opcjonalną.
MetroidFan2002
8
Są też chwile, kiedy trzeba upewnić się, że obiekt jest tej samej klasy, z którą porównujesz; na przykład lubię przesłonić metodę równości Object podczas tworzenia własnej klasy. Zawsze sprawdzam, czy obiekt wchodzący jest tej samej klasy.
StackOverflowed
58
Powiedziałbym też, że mówienie ludziom, że coś jest złego, bez dokładnego wyjaśnienia, dlaczego, lub podawanie odniesienia do artykułu, książki lub innego zasobu, w którym wyjaśniono problem, jest uważane za niekonstruktywne. Dlatego i wiedząc, że jestem w StackOverflow, nie wiem, dlaczego ludzie tak bardzo ocenili tę odpowiedź. Coś się tu zmienia ...
Adrián Pérez
15

W tym przypadku możemy użyć refleksji

objectName.getClass().getName();

Przykład:-

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

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

W takim przypadku otrzymasz nazwę klasy, którą obiekt przekazuje do HttpServletRequestzmiennej odniesienia interfejsu.

użytkownik1884500
źródło
to jest poprawne. użycie tylko obj.getClass()spowoduje zwrócenie nazwy klasy, przedrostek po słowieclass
x6iae
request.getClass().getName();drukuje wszystkie paczki! wraz z nazwą klasy
shareef 15.04.17
13

Istnieje również .isInstancemetoda Classklasy „ ”. jeśli uzyskasz klasę obiektu przez myBanana.getClass(), możesz sprawdzić, czy twój obiekt myApplejest instancją tej samej klasy, co myBananavia

myBanana.getClass().isInstance(myApple)
Andreas Petersson
źródło
1

sprawdzanie za pomocą isinstance()nie wystarczy, jeśli chcesz wiedzieć w czasie wykonywania. posługiwać się:

if(someObject.getClass().equals(C.class){
    // do something
}
Alon Gouldman
źródło
0

Używam funkcji blow w mojej klasie GeneralUtils, sprawdź, czy może być przydatna

    public String getFieldType(Object o) {
    if (o == null) {
        return "Unable to identify the class name";
    }
    return o.getClass().getName();
}
Ahmed Salem
źródło
0

Użyłem generycznych plików Java 8, aby uzyskać instancję obiektu w czasie wykonywania, zamiast konieczności używania wielkości liter

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

przekazać dowolny typ danych, a metoda wydrukuje typ danych przekazanych podczas ich wywoływania. na przykład

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

Poniżej znajduje się wynik

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 []
Saurabh Verma
źródło