값의 인덱스에 대한 일반적인 데이터 구조를 살펴보기 전에 유형의 인스턴스조차 this
매개 변수화되어 있는지 확인하고 싶습니다 .
그러나 Eclipse는 내가 이것을 할 때 불평합니다.
@Override
public int indexOf(Object arg0) {
if (!(arg0 instanceof E)) {
return -1;
}
이것은 오류 메시지입니다.
유형 매개 변수 E에 대해 instanceof check를 수행 할 수 없습니다. 런타임에 일반 유형 정보가 지워 지므로 삭제 오브젝트를 대신 사용하십시오.
더 좋은 방법은 무엇입니까?
답변
오류 메시지에 모두 나와 있습니다. 런타임에 유형이 사라 졌으므로 확인할 방법이 없습니다.
다음과 같이 객체를위한 팩토리를 만들어서 잡을 수 있습니다.
public static <T> MyObject<T> createMyObject(Class<T> type) {
return new MyObject<T>(type);
}
그런 다음 객체의 생성자에 해당 유형을 저장하므로 메소드가 다음과 같이 보일 수 있습니다.
if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass()))
{
return -1;
}
답변
제네릭을 사용한 런타임 유형 검사를위한 두 가지 옵션 :
옵션 1-생성자 손상
indexOf (…)를 재정의하고 전체 컬렉션을 반복하는 자신을 저장하기 위해 성능을 위해 유형을 확인하려고한다고 가정 해 봅시다.
다음과 같이 더러운 생성자를 만드십시오.
public MyCollection<T>(Class<T> t) {
this.t = t;
}
그런 다음 isAssignableFrom 을 사용 하여 유형을 확인할 수 있습니다 .
public int indexOf(Object o) {
if (
o != null &&
!t.isAssignableFrom(o.getClass())
) return -1;
//...
객체를 인스턴스화 할 때마다 스스로 반복해야합니다.
new MyCollection<Apples>(Apples.class);
가치가 없다고 결정할 수도 있습니다. ArrayList.indexOf (…) 구현 에서 형식이 일치하는지 확인하지 않습니다.
옵션 2-실패하자
알 수없는 유형이 필요한 추상 메소드를 사용해야하는 경우 실제로 원하는 것은 컴파일러가 instanceof 에 대한 울음을 멈추는 것 입니다. 다음과 같은 방법이 있다면 :
protected abstract void abstractMethod(T element);
다음과 같이 사용할 수 있습니다.
public int indexOf(Object o) {
try {
abstractMethod((T) o);
} catch (ClassCastException e) {
//...
컴파일러를 속이기 위해 객체를 T (일반 유형)로 캐스팅하고 있습니다. 캐스트는 런타임에 아무것도 수행하지 않지만 잘못된 유형의 객체를 추상 메소드에 전달하려고하면 여전히 ClassCastException이 발생합니다.
참고 1 : 추상 메소드에서 확인되지 않은 추가 캐스트를 수행하는 경우 여기에서 ClassCastException이 발생합니다. 그것은 좋거나 나쁠 수 있으므로 생각하십시오.
참고 2 : instanceof를 사용할 때 무료 null 검사가 제공됩니다 . 사용할 수 없으므로 맨손으로 null을 확인해야 할 수도 있습니다.
답변
오래된 게시물이지만 일반적인 instanceOf 검사를 수행하는 간단한 방법입니다.
public static <T> boolean isInstanceOf(Class<T> clazz, Class<T> targetClass) {
return clazz.isInstance(targetClass);
}
답변
클래스가 일반 매개 변수를 사용하여 클래스를 확장하면 런타임에 리플렉션을 통해이를 얻은 다음 비교를 위해 사용할 수 있습니다.
class YourClass extends SomeOtherClass<String>
{
private Class<?> clazz;
public Class<?> getParameterizedClass()
{
if(clazz == null)
{
ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass();
clazz = (Class<?>)pt.getActualTypeArguments()[0];
}
return clazz;
}
}
위의 경우 런타임에 getParameterizedClass ()에서 String.class를 가져 오며 캐시되므로 여러 검사시 리플렉션 오버 헤드가 발생하지 않습니다. ParameterizedType.getActualTypeArguments () 메소드에서 색인으로 다른 매개 변수화 된 유형을 얻을 수 있습니다.
답변
나는 같은 문제가 있었고 여기 내 해결책이 있습니다 (매우 겸손한 @george : 이번에는 컴파일하고 작동합니다 …).
내 probem은 Observer를 구현하는 추상 클래스 안에있었습니다. Observable은 모든 종류의 Object가 될 수있는 Object 클래스로 update (…) 메소드를 실행합니다.
T 타입의 객체 만 처리하고 싶습니다.
해결책은 런타임에 유형을 비교할 수 있도록 클래스를 생성자에 전달하는 것입니다.
public abstract class AbstractOne<T> implements Observer {
private Class<T> tClass;
public AbstractOne(Class<T> clazz) {
tClass = clazz;
}
@Override
public void update(Observable o, Object arg) {
if (tClass.isInstance(arg)) {
// Here I am, arg has the type T
foo((T) arg);
}
}
public abstract foo(T t);
}
구현을 위해 클래스를 생성자에게 전달하면됩니다.
public class OneImpl extends AbstractOne<Rule> {
public OneImpl() {
super(Rule.class);
}
@Override
public void foo(Rule t){
}
}
답변
또는 실패한 E 시도를 시도 할 수 있습니다.
public int indexOf(Object arg0){
try{
E test=(E)arg0;
return doStuff(test);
}catch(ClassCastException e){
return -1;
}
}
답변
기술적으로는 이것이 제네릭의 요점 일 필요는 없으므로 컴파일 유형 검사를 수행 할 수 있습니다.
public int indexOf(E arg0) {
...
}
그러나 클래스 계층 구조가 있으면 @Override가 문제가 될 수 있습니다. 그렇지 않으면 Yishai의 답변을 참조하십시오.