簡體   English   中英

Java 反思:如何獲取Class的實例<t>來自 ParameterizedType.getActualTypeArguments() 數組?</t>

[英]Java Reflection: How to obtain an instance of Class<T> from the ParameterizedType.getActualTypeArguments() array?

我想要做的是使用一個 Field 的通用 typearg

Type type = f.getGenericType();
if (type instanceof ParameterizedType) {
    ParameterizedType ptype = (ParameterizedType) type;
    // ...
    Class<?> typearg0 = ??? // ptype.getActualTypeArguments()[0]
}

(其中fjava.lang.Field的一個實例)。 我需要Class<?>的實例來執行Foo.class.isAssignableFrom(typearg0)檢查,它只需要Class<T> es作為參數。 同時,我知道(或期望)說typearg0也是參數化類型因此存在矛盾: typearg0不能同時是Class<?>ParameterizedType ,因為Class<?>本身就是 class 和不實現ParameterizedType

我可以以任何其他方式實現isAssignableFrom()檢查嗎? 或者我的目標通常是不可能實現的?

非常感謝!

編輯:

這是一個例子:

假設您期望Map<Foo, Set<Bar>>類型的 Field,但您得到的只是java.lang.reflect.Field實例。 現在,您不希望它精確匹配Map<Foo, Set<Bar>> ,您只希望各自的類型是MapSet實例 這不是嚴格的規范檢查,更像是“健全性檢查”。 我會嘗試這樣的檢查:

  1. 獲取字段類型為 class ( .getType() )
  2. 檢查Map是否可從字段類型分配
  3. 將字段類型作為(可能)參數化類型( .getGenericType()
  4. 檢查第一個泛型參數是否為Foo (這應該是完全匹配的)
  5. 獲取第二個通用參數作為 class
  6. 檢查Set是否可以從此嵌套類型分配
  7. 檢查嵌套類型本身是否為ParameterizedType並強制轉換
  8. 檢查嵌套類型的第一個泛型參數是否為Bar (這應該是完全匹配的)

但是,我不知道如何達到 5 和/或 6。

(使用 java 11)

就像您對Map所做的一樣, Set很可能是ParameterizedType的一個實例,因此您可以檢查它然后進行轉換。

從那個ParameterizedType (代表Set<Something> ),您可以使用getRawType來獲取Set 這也是一個Type ——但這應該可以安全地轉換為Class 以防萬一,您可以使用后備並使用其名稱加載 class。

final Type valueType = mapType.getActualTypeArguments()[1];
final ParameterizedType pValueType = (ParameterizedType) valueType;
final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
    ((Class<?>) pValueType.getRawType()) :
    // Should be castable, but just in case it's not, fallback
    getClass().getClassLoader().loadClass(
        pValueType.getRawType().getTypeName()
    );
if (Set.class.isAssignableFrom(valueClass)) { /* do something*/ }

這是一個完整的可運行示例

class Foo {}
class Bar {}
interface MyValidMap extends Map<Foo, Set<Bar>> {}

public class Application {
    public final HashMap<Foo, HashSet<Bar>> good = null;
    public final Map<Foo, Set<Bar>> better = null;
    public final String notAMap = null;
    public final Map<String, Set<Bar>> badKey = null;
    public final Map<Foo, List<String>> badValue = null;
    public final Map<Foo, Set<String>> badSetElems = null;
    public final MyValidMap noTypeParamMap = null;

    public static void main(String[] args) throws Exception {
        for (Field field : Application.class.getFields()) {
            System.out.println(field.getName() + " - " + fieldMatches(field));
        }
    }

    private static String fieldMatches(Field mapField) throws Exception {
        if (!Map.class.isAssignableFrom(mapField.getType())) {
            return "Field is not a Map";
        }

        if (!(mapField.getGenericType() instanceof ParameterizedType)) {
            // We know it's a map, but it doesn't have type params. Probably something
            // like this: class MyStringMap implements Map<String, String>. You can do
            // something with getGenericInterfaces() but this seems so unlikely that
            // it could just be ignored.
            return "TODO";
        }

        final ParameterizedType mapType = (ParameterizedType) mapField.getGenericType();
        final Type keyType = mapType.getActualTypeArguments()[0];
        final Type valueType = mapType.getActualTypeArguments()[1];
        if (Foo.class != keyType) {
            return "Map's key type is not Foo";
        }

        if (!(valueType instanceof ParameterizedType)) {
            // Same problem as above. May be a Set without type params
            return "Map's value is (probably) not a Set";
        }

        final ParameterizedType pValueType = (ParameterizedType) valueType;
        final Class<?> valueClass = pValueType.getRawType() instanceof Class ?
            ((Class<?>) pValueType.getRawType()) :
            Application.class.getClassLoader().loadClass(
                pValueType.getRawType().getTypeName()
            );

        if (!Set.class.isAssignableFrom(valueClass)) {
            return "Map's value is not a Set";
        }

        final Type setElemType = pValueType.getActualTypeArguments()[0];
        if (setElemType != Bar.class) {
            return "Set's elements are not Bars";
        }
        return "Looks good";
    }
}

Output:

good - Looks good
better - Looks good
notAMap - Field is not a Map
badKey - Map's key type is not Foo
badValue - Map's value is (probably) not a Set
badSetElems - Set's elements are not Bars
noTypeParamMap - TODO

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM