객체의 클래스를 결정하는 방법?


510

클래스 B와 클래스가 클래스를 C확장 A하고 유형의 객체를 가지고 B있거나 C인스턴스 인 유형을 어떻게 알 수 있습니까?


14
@starblue Casting이 가장 먼저 떠오를 것입니다. 필요하지 않은 경우 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)도 "true"출력을 제공하지만 의도는 그림에서 객체의 런타임 클래스를 찾는 것입니다. Parent1이 Child1 및 Child2에 의해 확장 된 경우 다음 code Child1 child1 = new Child1 ()을 시도하십시오 . Parent1 parentChild = 새 Child2 (); Child2 child2 = 새로운 Child2 (); (Parent1의 자식 1 인스턴스); (Child1의 child1 인스턴스); (Child2의 parentChild 인스턴스); (Parent1의 parentChild 인스턴스); (Child1의 parentChild 인스턴스); code 그것은 instanceof의 의도를 분명히 할 수 있습니다.
Bhavesh Agarwal

인터페이스 구축의 확실한 대안
JohnMerlino

3
단일 인터페이스를 구현하는 두 개의 클래스가있는 경우 어떻게합니까? 객체의 정확한 클래스를 어떻게 구별합니까?
olyv

3
그러나 obj가 null 인 경우 작동하지 않습니다. 그러면 해결책은 ParentInterface.class.isAssignableFrom (Child.class)입니다.
alexbt


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그러나 처리 에는 차이가 있습니다 .

  • 처음 2 개 방법에서 표현에 평가하는 false경우 obj이다 null( null아무것도의 인스턴스가 아닌).
  • 세 번째 방법은 NullPointerException분명히 던질 것 입니다.
  • 반대로 4 번째 및 5 번째 방법은 모든 유형으로 캐스트 할 수 null있기 때문에 수락 null합니다!

기억하기 : null 아니다 모든 유형의 인스턴스 있지만 캐스트 할 수 있는 유형.

노트

  • Class.getName()객체가 유형이 아닌 하위 클래스 인 경우 "is-instance-of" 테스트 베스 케이스 를 수행하는 데 사용해서는 안됩니다 C. 완전히 다른 이름과 패키지를 가질 수 있습니다 (따라서 클래스 이름이 분명히 일치하지 않음). 여전히 유형 C입니다.
  • 같은 상속 이유 Class.isAssignableFrom()대칭 이 아닙니다 : 의 유형 이의 서브 클래스 인 경우
    obj.getClass().isAssignableFrom(C.class)반환 false됩니다 .objC

6
이것은 다른 방법으로 많은 함정을 요약 한 것입니다. 완전히 작성해 주셔서 감사합니다!
Kelsin

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

제안 된 방법 중 하나를 사용하는 것은 잘못된 OO 설계에 기반한 코드 냄새로 간주됩니다.

당신의 디자인이 좋은 경우에, 당신은 자신이 사용할 필요 찾을 안 getClass()instanceof.

제안 된 방법 중 하나는 디자인 측면에서 명심해야 할 것입니다.


3
예, 아마도 getClass와 instanceof 사용의 99 %는 다형성 메소드 호출로 피할 수 있습니다.
Bill the Lizard

3
동의합니다. 이 경우 소유권이없는 잘 설계되지 않은 스키마에 따라 xml에서 생성 된 객체로 작업하고 있습니다.
캐리어

28
반드시 그렇지 않습니다. 때때로 인터페이스를 분리하는 것이 좋습니다. A가 B인지 알고 싶을 때가 있지만 대부분의 기능에는 A 만 필요하므로 B는 선택적 기능을 갖기 때문에 A를 B로 설정하지 않아도됩니다.
MetroidFan2002

8
또한 객체가 비교하는 클래스와 동일한 클래스인지 확인해야 할 때가 있습니다. 예를 들어 자신의 클래스를 만들 때 Object의 equals 메서드를 재정의하고 싶습니다. 나는 들어오는 객체가 같은 클래스인지 항상 확인합니다.
StackOverflowed

58
또한, 왜 사람들이 문제를 설명하는 종이, 책 또는 기타 자료에 대한 정확한 설명이나 설명을 제공하지 않고 나쁜 것을 말하는 것은 건설적이지 않은 것으로 간주됩니다. 따라서 내가 StackOverflow에 있다는 것을 알면 사람들이 왜이 답변을 많이지지했는지 알 수 없습니다. 뭔가 바뀌고 있습니다 ...
Adrián Pérez

15

이 경우에는 반사를 사용할 수 있습니다

objectName.getClass().getName();

예:-

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

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

이 경우 객체가 HttpServletRequest인터페이스 참조 변수에 전달하는 클래스의 이름을 얻습니다 .


이것이 맞습니다. 를 사용 obj.getClass()하면 className, prefixex라는 단어가 반환됩니다class
x6iae

request.getClass().getName();모든 패키지를 인쇄합니다! 클래스 이름과 함께
shareef

13

.isInstance" Class"클래스 에도 메소드 가 있습니다 . via myBanana.getClass()를 통해 객체의 클래스를 얻는 다면 객체 myApplemyBananavia 와 동일한 클래스의 인스턴스 인지 확인할 수 있습니다

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 []
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.