Java泛型函数:如何返回泛型类型

Java泛型函数:如何返回泛型类型,java,generics,Java,Generics,下面是一个Java通用模式: public <T> T getResultData(Class<T> resultClass, other_args) { ... return resultClass.cast(T-thing); } 当所需的返回类型本身是泛型的时,我从来没有弄清楚如何干净地使用此模式。具体来说,如果像这样的函数想要返回Map,该怎么办?当然,由于您无法为泛型获取类对象,因此唯一的选择是传递Map.class,然后您需要强制转换和@Sup

下面是一个Java通用模式:

public <T> T getResultData(Class<T> resultClass, other_args) { 
   ...
   return resultClass.cast(T-thing);
}
当所需的返回类型本身是泛型的时,我从来没有弄清楚如何干净地使用此模式。具体来说,如果像这样的函数想要返回
Map
,该怎么办?当然,由于您无法为泛型获取类对象,因此唯一的选择是传递
Map.class
,然后您需要强制转换和
@SuppressWarning

最后一个电话是这样的:

Map<String, String> returnedMap;
returnedMap = thing.getResultData(Map.class, some_other_args);
有鉴于此,被调用函数可以提取基类型并将其用于强制转换或新建实例,但伪字段business看起来确实很难看

注意,像这样的函数并不总是调用
newInstance
。显然,如果他们这样做了,他们就不需要调用
resultClass.cast

如果您想使用类型安全容器类,就可以使用它。它们用于提供类型安全绑定。有关更多示例和类,请参见Guice源代码

顺便说一下,如果您调用
resultClass.newInstance()
,则不需要强制转换

public <T> T getResultData(Class<T> resultClass, other_args) {       
   ...
   return resultClass.newInstance();
}
public T getResultData(类resultClass,其他参数){
...
返回resultClass.newInstance();
}

如果我正确理解了您真正想要做的是(非法的伪语法):

public T getResultData(类resultClass,其他参数){
...
返回resultClass.cast(T-thing);
}
不能,因为不能进一步参数化泛型类型
t
。乱搞
java.lang.reflect.*
不会有帮助:

  • 没有
    Class
    这样的东西,因此无法动态创建其实例
  • 无法实际将所讨论的方法声明为返回
    T
  • 嗯,。这里有一个丑陋的(部分的)解决方案。不能对泛型参数进行泛型参数化,因此无法编写

    public <T<U,V>> T getResultData ...
    
    public T getResultData。。。
    
    但您可以返回参数化集合,例如,对于集合

    public < T extends Set< U >, U > T getResultData( Class< T > resultClass, Class< U > paramClass ) throws IllegalAccessException, InstantiationException {
            return resultClass.newInstance();
        }
    
    public,U>T getResultData(类resultClass,类paramClass)抛出IllegaAccessException,实例化Exception{
    返回resultClass.newInstance();
    }
    

    如果U-param存在于类签名中,则可以将其删除。

    在标准Java API中无法做到这一点。但是,也有一些实用程序类可以从泛型类中获得好处。例如,在GoogleGSON(它将JSON转换为fullworthy Javabeans,反之亦然)中,有一个类。您可以按如下方式使用它:

    List<Person> persons = new Gson().fromJson(json, new TypeToken<List<Person>>() {}.getType());
    
    List persons=new Gson().fromJson(json,new TypeToken(){}.getType());
    

    这样的结构正是您所需要的。你可以找到sode的来源,你可能会发现它也很有用。它只需要一个额外的
    getResultData()
    方法,可以接受
    类型

    是的,我认为这是不可能的

    想象一下这种情况。您有一个包含要读取的序列化对象的文件。如果将函数设置为泛型,则无需强制转换即可使用它。但假设您有一个序列化为文件的映射

    当您反序列化它时,无法知道原始泛型映射类型是什么。就java而言,它只是一张地图

    我在列表中遇到了这个问题,这很烦人。但实际上我最终做的是创建一个通用的“转换集合”类,它接受一个集合和一个“转换器”(可以是匿名内部类型)


    然后,当您迭代转换集合时,每个项都会被转换。这就解决了警告问题。要想摆脱这个警告需要做很多工作,但我不认为这是我提出这个框架的主要原因。您还可以执行更强大的操作,例如获取文件名集合,然后编写一个转换器来加载文件中的数据,或者执行查询,等等

    如果您确实不需要映射的确切泛型类型,并且您的代码不依赖于该类型,但您只是对可能编写的警告感到恼火:

    Map<?, ?> returnedMap;
    returnedMap = thing.getResultData(Map.class, some_other_args);
    
    Map返回地图;
    returnedMap=thing.getResultData(Map.class,一些其他参数);
    
    然后,您可以使用任何未进行类型参数化的map方法,如containsKey、clear、iterator等,或者在entrySet上迭代,或者将returnedMap传递给任何泛型方法,所有操作都是类型安全的

    Map<?, ?> returnedMap;
    returnedMap = thing.getResultData(Map.class, some_other_args);
    
    Object myKey = ...;
    
    Object someValue = returnedMap.get(myKey);
    
    for (Iterator<? extends Map.Entry<?,?>> it = returnedMap.entrySet().iterator(); it.hasNext(); )
      if (it.next().equals(myKey))
        it.remove();
    
    for (Map.Entry<?,?> e : returnedMap.entrySet()) {
      if (e.getKey().equals(myKey))
        e.setValue(null); // if the map supports null values
    }
    
    doSomething(returnedMap);
    
    ...
    
    <K,V> void doSomething(Map<K,V> map) { ... }
    
    Map返回地图;
    returnedMap=thing.getResultData(Map.class,一些其他参数);
    对象myKey=。。。;
    objectsomevalue=returnedMap.get(myKey);
    for(Iterator>it=returnedMap.entrySet().Iterator();it.hasNext();)
    if(it.next().equals(myKey))
    it.remove();
    对于(Map.Entry e:returnedMap.entrySet()){
    如果(例如getKey().equals(myKey))
    e、 setValue(null);//如果映射支持null值
    }
    doSomething(返回的地图);
    ...
    void doSomething(Map){…}
    

    实际上,在不知道其键或值类型的情况下,可以通过类型安全的方式使用映射执行许多操作。

    除非您无法获取并因此传递类实例作为泛型类,如
    Map
    ,因此这对OP的问题毫无帮助。是的。这正是我们如何做到这一点的。他们在语言中不受支持,但你使用Neal Gafter发明的TypeLiteral。如果您将TypeLiteral引用编辑为实际答案,我会向上投票。@chsply76:碰巧,Map有一个GenericType对象。如果您有一个Map类型的字段,并调用field.getGenericType,您将得到它。然而,获取其中一个的唯一方法实际上是从字段或返回类型的反射中获取它。是的,有,是的,您可以从字段/方法声明中获取。不,它与
    Class
    不同,因此对您没有任何帮助:您不能对其进行强制转换,也不能仅使用
    ParameterizedType
    创建相应类的实例。
    List<Person> persons = new Gson().fromJson(json, new TypeToken<List<Person>>() {}.getType());
    
    Map<?, ?> returnedMap;
    returnedMap = thing.getResultData(Map.class, some_other_args);
    
    Map<?, ?> returnedMap;
    returnedMap = thing.getResultData(Map.class, some_other_args);
    
    Object myKey = ...;
    
    Object someValue = returnedMap.get(myKey);
    
    for (Iterator<? extends Map.Entry<?,?>> it = returnedMap.entrySet().iterator(); it.hasNext(); )
      if (it.next().equals(myKey))
        it.remove();
    
    for (Map.Entry<?,?> e : returnedMap.entrySet()) {
      if (e.getKey().equals(myKey))
        e.setValue(null); // if the map supports null values
    }
    
    doSomething(returnedMap);
    
    ...
    
    <K,V> void doSomething(Map<K,V> map) { ... }