理解Java中的泛型

理解Java中的泛型,java,generics,Java,Generics,我正在构建一些返回任何类型对象集合的通用代码。这是我的身材: public class Util{ public static <T, R extends Collection> R a(Collection<T> collection) { return (R) collection; } public static <T> List<T> listWith(T... items) { r

我正在构建一些返回任何类型对象集合的通用代码。这是我的身材:

public class Util{
    public static <T, R extends Collection> R a(Collection<T> collection) {
        return (R) collection;
    }

    public static <T> List<T> listWith(T... items) {
        return Arrays.asList(items);
    }

    public static <T> Set<T> setWith(T... items) {
        return new HashSet<>(Arrays.asList(items));
    }
}
我的想法是,通过这个Util类,我可以创建任何对象类型的列表或集合,比如:

List<String> list = a(listWith("str1", "str2"));
Set<Object> set = a(setWith(new Object(), new Object()));
我现在有两个问题:

如何将左侧的Obj类型限制为与传递给listWith方法的参数的Obj类型相同?因为现在我可以这样做:Set Set=asetwithnewobject,newobject;没有任何编译错误 如何将方法的返回类型限制为扩展集合的唯一类。现在我可以这样做:User=alistWithtest;也没有编译错误,但它会抛出一个强制转换异常。我在上面尝试过使用返回类型作为R扩展集合,但没有成功 如何将左侧的Obj类型限制为与传递给listWith方法的参数的Obj类型相同

不要使用集合的原始类型,并将其限制为泛型类型

public static <T, R extends Collection<T>> R a(Collection<T> collection) { 
    return (R) collection;
}
应用答案的第二部分后:

List<String> list = a(listWith("str1", "str2"));           // compiles
Set<Object> set = a(setWith(new Object(), new Object()));  // compiles

Set<String> set2 = a(setWith(new Object(), new Object())); // doesn't compile
User user = a(listWith("test"));                           // doesn't compile
这个限制对于这个简单的情况是有效的,但毫无意义。你可以在@DmytroMitin's找到进一步的解释

如您所见,2的整个应用程序最终返回输入本身,这给了我一个问题:

是否需要这种通用包装

我只想在@Nikolas的回答中补充一下为什么他的修正1

public static <T, R extends Collection<T>> R a(Collection<T> collection) { 
    return (R) collection;
}
这是我的。。。似乎不是有效的语法,但如果我们定义

class User {}
class SubUser extends User implements Collection<String>{ ... }

仍然是可能的。

不要使用原始类型,将泛型类型定义更改为,您将得到编译时错误。问题是类型是在调用站点选择的。例如,您可以同时执行List=asomething;Set=asomething;-其中至少有一个可能会失败,因为有些东西可能既不是集合也不是列表。在这种情况下,最好只执行显式强制转换,否则将调用。R aCollection集合,但为什么不直接在listWith和setWith方法中返回它呢?还有,为什么要用不同的名称包装asList?资产将是一个很好的增强。我想还有一个问题可能是为什么使用fix1user=alistWithtest;编译。在修复程序2中,返回同一个集合也可以使a变得微不足道。假设a做了一些工作:公共静态R aCollection集合{collection res=…;对于T T:collection{res.addnew Tuplet,T;}返回R res;}。在这种情况下,修复2似乎是不可能的。但是User=alistWithtest;编译。因此,这并没有回答OP的第二个问题:如何将返回类型限制为扩展集合的唯一类。您的代码不符合我的第二个修复。我建议的是应收账款收集,而你坚持使用收款收集。因此,实际执行公共静态R aR集合{collection res=new ArrayList;对于T T:collection{res.addnew Tuplet,T;}返回R res;}的方法不允许User User=alistWithtest;是的,但这个签名是一个谎言,因为铸造可能。实际上,您接受集合的子类型并返回集合的子类型。签名正确的公共静态R1 aR collection User=alistWithtest;我终于明白你的目标了。我回答的真正目的是进入最后一步的过程:省略整个包装器。我认为在这种情况下不可能真正限制返回类型。
public static <T, R extends Collection<T>> R a(Collection<T> collection) { 
    return (R) collection;
}
User user = Util.<String, User & Collection<String>>a(listWith("test"));
class User {}
class SubUser extends User implements Collection<String>{ ... }
User user = Util.<String, SubUser>a(listWith("test"));
class SubUser<T> extends User implements Collection<T> {...}