2012-03-29 163 views
1
public class A<T> { 
    public <K> void m(A<K> target) { 
     // determine if T equals K 
    } 
} 

是否可以檢查<T><K>是否是相同的類型?確定泛型類型是否相同

+0

IIRC,類型信息在運行時被擦除(爲了向後兼容非泛型代碼)。因此,我很肯定答案是否定的。 – jpm 2012-03-29 18:55:48

+2

這不是一個適當的泛型使用 – ControlAltDel 2012-03-29 18:56:31

+0

我敢肯定,這是使用泛型的可能和正常情況之一。 – 2012-03-29 18:59:53

回答

6

是,這種工作方式的一般TypeReference相同。通常,類型被刪除,但它與匿名內部類作品:

public abstract class A<T> { 

    private Type type; 

    public A() { 
     Type superclass = getClass().getGenericSuperclass(); 
     this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0]; 
    } 

    public <K> void m(A<K> target) { 
      System.out.println(type.equals(target.type)); 
    } 
} 

要使用它:

A<String> as = new A<String>(){}; 
    A<String> a2s = new A<String>(){}; 
    A<Integer> ai = new A<Integer>(){}; 

    as.m(a2s); // prints true 
    as.m(ai); // prints false 

類並不一定是抽象的,但它作爲一個提醒,使其匿名內部類。唯一真正的缺點是你必須把{}結束。

+0

你的邪惡攻擊與抽象類的加分 - 但OP,通常沒有任何方法可以做到這一點,沒有「匿名內部類」攻擊,絕對沒有辦法做到這一點。 – 2012-03-29 19:30:49

+0

葉普,他們必須是匿名的內部類,更新我的答案 – Andrejs 2012-03-29 19:51:09

0

不是真的,只有當你有一個T的實例或者類傳入A或想要比較它們的方法。類型擦除...

1

沒有,你能來最接近的是:

public class A<T> { 
    private Class<T> _type; 

    public A(Class<T> type) { 
    assert type != null; 
    _type = type; 
    } 

    public <K> void m(A<K> target) { 
    if (target != null && target._type == this._type) { 
     ... 
    } 
    } 

你可以看到在類型傳遞Class<T>作爲構造函數的參數一樣EnumMap的成語。

2

這並不容易,因爲javas類型的擦除。在運行時,T和K的類型信息丟失。

但如果你能得到那些你可以檢查那些在編譯時類型的實例:

public class A<T> { 

    private T t; 

    public T getT() { return t; } 

    public A(T t) { 
     this.t = t; 
    } 

    public <K> m(A<K> target) { 
     // determine if T equals K 
     boolean areEqual = t.getClass().equals(target.getT().getClass()); 
    } 
} 

但是這意味着你需要訪問對象的實例。

+0

問題是'getT()'可以返回'null' – 2012-03-29 19:04:08

+0

這是真的。你可以在之前檢查並設置areEqual爲false。 – david 2012-03-29 19:05:39

0

這是我寫的代碼,它會告訴你一個類的泛型類型。使用此來比較泛型類型A對target.getClass():

/** 
* Gets a list of type Class that contains the type arguments that a child class has used to extend a generic base 
* class. 
* 
* For example, if a class called ChildClass has this signature: 
* 
* <code> 
* public class ChildClass extends ParentClass<Integer, String> 
* </code> 
* 
* then the list returned would have two entries: Integer and String. 
* 
* @param baseClass The generic base class being extended. 
* @param childClass The child class that is doing the extending. 
* @return A list of type Class containing the raw classes for the type arguments. 
*/ 
public <T> List<Class<?>> getTypeArguments(Class<T> baseClass, Class<? extends T> childClass) { 

    Map<Type, Type> resolvedTypes = new HashMap<Type, Type>(); 
    Type type = childClass; 

    // start walking up the inheritance hierarchy until we hit baseClass 
    while (getClass(type) != null && !getClass(type).equals(baseClass)) { 
     if (type instanceof Class) { 
      // there is no useful information for us in raw types, so just keep going. 
      type = ((Class<?>) type).getGenericSuperclass(); 
     } else { 
      ParameterizedType parameterizedType = (ParameterizedType) type; 
      Class<?> rawType = (Class<?>) parameterizedType.getRawType(); 

      Type[] actualTypeArguments = parameterizedType.getActualTypeArguments(); 
      TypeVariable<?>[] typeParameters = rawType.getTypeParameters(); 
      for (int i = 0; i < actualTypeArguments.length; i++) { 
       resolvedTypes.put(typeParameters[i], actualTypeArguments[i]); 
      } 

      if (!rawType.equals(baseClass)) { 
       type = rawType.getGenericSuperclass(); 
      } 
     } 
    } 

    // finally, for each actual type argument provided to baseClass, determine (if possible) the raw class for that 
    // type argument 
    Type[] actualTypeArguments; 
    if (type instanceof Class) { 
     actualTypeArguments = ((Class<?>) type).getTypeParameters(); 
    } else { 
     actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments(); 
    } 

    // convert types to their raw classes 
    List<Class<?>> typeArgumentsAsClasses = new ArrayList<Class<?>>(); 
    for (Type baseType : actualTypeArguments) { 
     while (resolvedTypes.containsKey(baseType)) { 
      baseType = resolvedTypes.get(baseType); 
     } 
     typeArgumentsAsClasses.add(getClass(baseType)); 
    } 

    return typeArgumentsAsClasses; 

} 

/** 
* Gets the Class for a Type. If the Type is a variable type, null is returned. 
* 
* @param type The Type to get the Class for 
* @return Returns the Class, unless Type is a variable type, then null is returned. 
*/ 
public Class<?> getClass(Type type) { 

    Class<?> returnClass = null; 

    if (type instanceof Class) { 
     returnClass = (Class<?>) type; 
    } else if (type instanceof ParameterizedType) { 
     returnClass = getClass(((ParameterizedType) type).getRawType()); 
    } else if (type instanceof GenericArrayType) { 
     Class<?> componentClass = getClass(((GenericArrayType) type).getGenericComponentType()); 
     if (componentClass != null) { 
      returnClass = Array.newInstance(componentClass, 0).getClass(); 
     } 
    } 

    return returnClass; 

}