IT이야기

Java: 인스턴스(Instanceof) 및 제네릭

cyworld 2022. 5. 8. 22:05
반응형

Java: 인스턴스(Instanceof) 및 제네릭

값의 인덱스에 대한 일반적인 데이터 구조를 살펴보기 전에 해당 유형의 인스턴스(instance)인지 확인하십시오.this에 대한 파라메트릭을 받았어

하지만 이클립스는 내가 이렇게 하면 불평을 한다.

@Override
public int indexOf(Object arg0) {
    if (!(arg0 instanceof E)) {
        return -1;
    }

오류 메시지:

형식 매개 변수 E에 대해 검사 인스턴스(instance)를 수행할 수 없음.런타임에 일반 유형 정보가 지워지므로 삭제 개체 대신 사용

그것을 하는 더 좋은 방법은 무엇인가?

에러메세지에 다 나와 있어.런타임에 타입이 없어져서 확인할 방법이 없다.

이렇게 목적지에 맞는 공장을 만들면 잡을 수 있을 것이다.

 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 - 실패 허용

만약 당신이 당신의 알 수 없는 타입을 필요로 하는 추상적인 방법을 사용해야 한다면, 당신이 정말로 원하는 것은 컴파일러가 인스턴스 에 대해 우는 것을 멈추는 것이다.이와 같은 방법을 사용할 경우:

protected abstract void abstractMethod(T element);

다음과 같이 사용할 수 있다.

public int indexOf(Object o) {

    try {

        abstractMethod((T) o);

    } catch (ClassCastException e) {

//...

당신은 컴파일러를 속이기 위해 T(당신의 일반형)에게 그 대상을 던져주는 것이다.당신의 출연진들은 런타임에 아무 것도 하지 않지만, 당신이 당신의 추상적인 방법에 잘못된 유형의 오브젝트를 전달하려고 할 때 당신은 여전히 ClassCastException을 받게 될 것이다.

비고 1: 추상적인 방법으로 확인되지 않은 추가 깁스를 하는 경우, ClassCastExceptions가 여기에서 잡힐 것이다.좋을 수도 있고 나쁠 수도 있으니까 잘 생각해 봐.

참고 2: 인스턴스(instanceof) 사용할 때 무료 null 수표를 받으십시오.사용할 수 없기 때문에 맨손으로 null 여부를 확인해야 할 수도 있다.

이전 게시물이지만 일반 인스턴스 확인을 수행하는 간단한 방법.

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() 방법에서 인덱스별로 다른 매개 변수화된 유형을 가져올 수 있다는 점에 유의하십시오.

나는 같은 문제를 가지고 있었고, 여기에 나의 해결책이 있다(매우 겸손, @gee: 이번에는 컴파일 AND working...).

내 프로템은 옵저버를 구현하는 추상 수업 안에 있었다.관측 가능한 화재 방법은 어떤 종류의 물체가 될 수 있는 객체 클래스로 업데이트된다(...).

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는 클래스 계층이 있으면 문제가 될 수 있다.그렇지 않으면 이샤이의 대답을 본다.

객체의 런타임 유형은 필터링할 수 있는 비교적 임의적인 조건이다.나는 너의 수집품에 그런 더러운 것을 가까이 하지 말 것을 제안한다.이는 단순히 필터의 수집 담당자가 구조물을 통과함으로써 달성된다.

public interface FilterObject {
     boolean isAllowed(Object obj);
}

public class FilterOptimizedList<E> implements List<E> {
     private final FilterObject filter;
     ...
     public FilterOptimizedList(FilterObject filter) {
         if (filter == null) {
             throw NullPointerException();
         }
         this.filter = filter;
     }
     ...
     public int indexOf(Object obj) {
         if (!filter.isAllows(obj)) {
              return -1;
         }
         ...
     }
     ...
}

     final List<String> longStrs = new FilterOptimizedList<String>(
         new FilterObject() { public boolean isAllowed(Object obj) {
             if (obj == null) {
                 return true;
             } else if (obj instanceof String) {
                 String str = (String)str;
                 return str.length() > = 4;
             } else {
                 return false;
             }
         }}
     );

Java가 결정하도록 하고 예외적인 최종 결론을 얻도록 한다.

public class Behaviour<T> {
    public void behave(Object object) {
        T typedObject = null;
        
        try { typedObject = (T) object; }
        catch (ClassCastException ignored) {}
        
        if (null != typedObject) {
            // Do something type-safe with typedObject
        }
    }
}

참조URL: https://stackoverflow.com/questions/1570073/java-instanceof-and-generics

반응형