문제
다음과 같은 수업이 있다고 가정해 보겠습니다.
public class Test<E> {
public boolean sameClassAs(Object o) {
// TODO help!
}
}
그걸 어떻게 확인하겠어요? o
와 같은 클래스야 E
?
Test<String> test = new Test<String>();
test.sameClassAs("a string"); // returns true;
test.sameClassAs(4); // returns false;
메소드 서명을 다음에서 변경할 수 없습니다. (Object o)
슈퍼클래스를 재정의하므로 메서드 서명을 선택할 수 없습니다.
또한 캐스트를 시도한 다음 실패할 경우 결과 예외를 포착하는 방식을 택하지 않을 것입니다.
해결책
다음의 인스턴스 Test
무엇인지에 대한 정보가 없습니다 E
런타임 중입니다.따라서 다음을 통과해야 합니다. Class<E>
Test의 생성자에.
public class Test<E> {
private final Class<E> clazz;
public Test(Class<E> clazz) {
if (clazz == null) {
throw new NullPointerException();
}
this.clazz = clazz;
}
// To make things easier on clients:
public static <T> Test<T> create(Class<T> clazz) {
return new Test<T>(clazz);
}
public boolean sameClassAs(Object o) {
return o != null && o.getClass() == clazz;
}
}
"instanceof" 관계를 원하면 다음을 사용하십시오. Class.isAssignableFrom
대신에 Class
비교.메모, E
같은 이유로 제네릭이 아닌 유형이어야 합니다. Test
필요하다 Class
물체.
Java API의 예는 다음을 참조하세요. java.util.Collections.checkedSet
그리고 유사합니다.
다른 팁
제가 늘 사용해오던 방법은 아래와 같습니다.그것은 고통스럽고 약간 추악하지만 더 나은 것을 찾지 못했습니다.Generic이 컴파일되면 클래스 정보가 손실되므로 생성 시 클래스 유형을 전달해야 합니다.
public class Test<E> {
private Class<E> clazz;
public Test(Class<E> clazz) {
this.clazz = clazz;
}
public boolean sameClassAs(Object o) {
return this.clazz.isInstance(o);
}
}
다음과 같이 작동하도록 만들 수 있습니다.
public class Test<E> {
private E e;
public void setE(E e) {
this.e = e;
}
public boolean sameClassAs(Object o) {
return (o.getClass().equals(e.getClass()));
}
public boolean sameClassAs2(Object o) {
return e.getClass().isInstance(o);
}
}
나도 똑같은 일을 하려고 했는데 방금 깨달은 한 가지 멋진 요령은 캐스트를 시도할 수 있고 캐스트가 실패하면 ClassCastException이 발생한다는 것입니다.당신은 그것을 잡을 수 있고 무엇이든 할 수 있습니다.
따라서 sameClassAs 메소드는 다음과 같아야 합니다.
public boolean sameClassAs(Object o) {
boolean same = false;
try {
E t = (E)o;
same = true;
} catch (ClassCastException e) {
// same is false, nothing else to do
} finally {
return same;
}
}