※ 引述《jtorngl (DDFL)》之铭言:
: 请问 Collection 不支援 covariance (还是该说泛型不支援 covariance)
: 所以 summary 只能传入 List<Number> 的物件
: 而不能传入 List<Integer>、List<Double>, ...
: public double summary(List<Number> nums) {
你只能传 List<Number>,不能传 List<Integer> 等…
: 为了让这段程式能达到类似 covariance 机制
: 所以会使用 wildcard
: public double wildcardSummary(List<? extends Number> nums) {
你可以传 List<Number>、List<Integer> 等…
: 不过泛型使用 extends 一样可以做到不是吗
: private <E extends Number> double genericsSummary(List<E> nums) {
你必须先确定 E 真正的型态,而这个 E 只能是 Number 的子类,一旦 E 确认了
,例如 Number,那么你就只能传 List<Number>…
是的,这也可以解决 List<? extends Number> 能解决的问题,不过语法意义上
是不同的,只不过两者正好涵盖了相同的问题。
因为正好能解决相同问题,就简洁度来说, List<? extends Number> 会是我想
要的写法,因为只要出现一次角括号…
另一方面,若是个 instance method,通常会以类别上的型态限定为主,例如:
public class Test<E> {
public E foo(List<? extends Number> nums)
{
return null;
}
}
会在方法前使用型态限定,通常是在 static method 时,例如:
public class Test {
public static <E extends Number> Some foo(E e)
{
return null;
}
}
: 目前能想到的只有,wildcard 有 super 来达到 contravariance
: 但是泛型只支援 extends 而没有支援 super
: 那如果没有要 contravariance 的效果
: 有什么情况是 wildcard 才能做到,而泛型还是不能编译的?
不要从能不能编译来看,很多情况其实都可以通过编译,你要看你想解决什么
,以及可读性哪个比较好。
: 目前看一些文章,在方法的参数,要限制参数型态边界时
: 几乎都是使用 List<? extends Number>
: 好像比较少看到 <E extends Number> ... List<E>
: 看了一下 JDK 的 List interface
: boolean addAll(Collection<? extends E> c);
: 是因为限制的参数型态都是动态,才只能用 wildcard 吗?
不是,理由上面说过,你想看到更多 <E extends Number> 的应用,可以找找
有 static method 的类别,例如 Collections..
static <T extends Object & Comparable<? super T>>
T maxCollection<? extends T> coll)
static <T extends Comparable<? super T>>
void sortList<T> list)
: 以JDK 的 List 接口来说
: public interface List<E> extends Collection<E>
: 有一个方法是 boolean containsAll(Collection<?> c);
:
: 如果是这样定义的
: boolean containsAll(Collection<E> c);
:
: 那当我们建立 List<String> strs = Arrays.asList("1", "2");
: 那这个 strs 的 containsAll 方法,只能用来比较 String 集合了
:
: 反之因为使用 ? 定义
: boolean containsAll(Collection<?> c); 这样定义
: 所以 strs 还是可以用来比对各种型态的集合
这就是两者应用上的差别之一…instance method 通常会以类别上宣告的型态来限定,
因为阅读上比较简单。
也可以进一步看看这边的文件:
https://openhome.cc/Gossip/JavaEssence/WildCard.html
作者:
qrtt1 (有些事,有时候。。。)
2020-08-30 21:42:00是良葛格!
作者:
jtorngl (Pedrosa go!)
2020-08-31 12:58:00感谢良葛格的说明,Java SE8 技术手册有买,不过第18章没翻XD,学习笔记的静态方法泛型倒是有看不懂的地方,就是BeanUtil.<Student>getBean(...) 的用法,在方法名称前面加上 <型别> 只是为了炼呼叫,不加会编译错误public static <T> T obtain(T t) { return t; }我有试着练习一个泛型方法GenericMethod.staticObtain("abc").toUpperCase();GenericMethod.<String>obtain("abc").toUpperCase();发现没加 <String> 还是可以编译和执行,所以有点搞不懂JDK java-11-openjdk-11.0.8.10-2.windows.redhat.x86_64没加<String> 不是打错,是推文长度不够,改名忘了改到
作者:
tw11509 (John-117)
2020-08-31 20:08:00java 8之后大部分的情况就不用加了,编译器会自己推断出来
作者:
jtorngl (Pedrosa go!)
2020-09-01 11:18:00感谢良葛格说明,原来是方法的参数没有型态让编译知道static <T> T jsonToObj(String json, Class<T> clazz)我使用的方法都会在方法参数带<T>,所以不知道那种用法这种型态推断蛮强大的,但就和初学lambda一样,对语法不熟悉时,会觉得为什么可以这样啊?!