关于Java泛型的下限用法:? super T

7 浏览
0 Comments

关于Java泛型的下限用法:? super T

我正在努力深入理解下界通配符的用法。我正在尝试编写一个通用的方法copy,它将一个List的内容复制到另一个List中。我想出了这个方法的签名:

 void copy(List dest, List src)

我认为这个签名详尽地解决了所有情况。然而,我看到在Java的Collections类中,方法的签名是这样的:

 void copy(List dest, List src)

我不明白为什么他们使用List dest而不是简单地List dest。他们的签名有额外的灵活性吗?

0
0 Comments

Java中的泛型(Generics)是一种强大的特性,它允许我们在编译时进行类型检查,以确保代码的类型安全性。然而,有时我们可能会遇到一些令人困惑的问题,其中之一就是使用下界(Lower Bound)通配符时的类型推断问题。

在上述示例中,我们可以看到有两个copy方法的签名。第一个方法使用了下界通配符? super T,而第二个方法则没有使用通配符。我们会发现,当我们尝试执行obj.copy(lm, lhm)时,第一个方法会通过编译,而第二个方法则会报错。

那么为什么会出现这样的情况呢?原因在于类型推断的问题。在第二个方法中,由于没有使用下界通配符,编译器会根据参数的类型进行类型推断。在这种情况下,我们传入的参数类型是List<HashMap<String,String>>List<? extends HashMap<String,String>>,由于参数类型不一致,编译器会报错。

而在第一个方法中,我们使用了下界通配符? super T,这意味着我们可以接受T的超类作为参数。在这种情况下,编译器会将List<Map<String,String>>作为List<? super HashMap<String,String>>的超类型进行推断,因为HashMap<String,String>Map<String,String>的子类。所以,编译器会通过编译。

为了解决这个问题,我们可以使用下界通配符? super T,这样就可以接受T的超类作为参数。这样一来,我们就可以传入List<Map<String,String>>作为List<? super HashMap<String,String>>的参数,从而使代码通过编译。

我们可以看到,在Java中使用下界通配符? super T可以解决类型推断的问题。通过使用下界通配符,我们可以接受T的超类作为参数,从而使代码具有更高的灵活性和可复用性。

0
0 Comments

在Java的泛型中,使用? super T的原因是为了更明确地指定dest应该接受的类型。与T相比,? super T只是一种风格上的差异,但这是更好的实践,这可以通过应用一些良好代码原则来看出:

- 显式意图:使用? super T更清楚地显示dest应该接受的类型。

- 模块化:你根本不需要查看src上的类型约束就知道dest可以接受哪些类型。

- PECS原则:生产者参数(下面的"in")应该使用extends,而消费者参数(下面的"out")应该使用super关键字。

使用? super T也是Java教程推荐的(它们甚至使用了一个copy函数):

引用如下:

“对于本讨论,将变量视为提供两个功能之一是有帮助的:

- “in”变量:它向代码提供数据。想象一个带有两个参数的copy方法:copy(src, dest)src参数提供要复制的数据,因此它是“in”参数。

- “out”变量:它保存供其他地方使用的数据。在copy示例中,copy(src, dest)dest参数接受数据,因此它是“out”参数。

在决定是否使用通配符及何种类型的通配符时,可以使用“in”和“out”原则。以下是遵循的准则:

- 使用上边界通配符定义“in”变量,使用extends关键字。

- 使用下边界通配符定义“out”变量,使用super关键字。”

这个问题在这里也有答案。其中展示了它们等价的所有情况,这是特别有说服力的。

0