我对Java泛型如何处理继承/多态性感到困惑.
假设以下层次结构 -
动物(父母)
狗 - 猫(儿童)
所以假设我有一个方法doSomething(List<Animal> animals).根据所有继承和多态的规则,我会假设a List<Dog> 是 a List<Animal>而a List<Cat> 是 a List<Animal>- 所以任何一个都可以传递给这个方法.不是这样.如果我想实现这种行为,我必须明确告诉该方法接受一个Animal的任何子类的列表doSomething(List<? extends Animal> animals).
我知道这是Java的行为.我的问题是为什么?为什么多态通常是隐含的,但是当涉及泛型时必须指定它?
public class Test {
static List<Object> listA = new ArrayList<>();
public static void main(final String[] args) {
final List<TestClass> listB = new ArrayList<>();
listB.add(new TestClass());
// not working
setListA(listB);
// working
setListA(listB.stream().collect(Collectors.toList()));
System.out.println();
}
private static void setListA(final List<Object> list) {
listA = list;
}
}
Run Code Online (Sandbox Code Playgroud)
为什么它适用于流,并不适用于简单的集合?
Set<Object> removedObjs = new HashSet<>();
List<? extends MyEntity> delObjs = (List<? extends MyEntity>) new ArrayList<>(removedObjs);
Run Code Online (Sandbox Code Playgroud)
MyEntity 是标记界面.
上面的代码在java-7(java版本"1.7.0_91",准确)中工作正常,但在java-8(java版本"1.8.0_77")中没有
在Java8中,我收到以下异常:
incompatible types: ArrayList<Object> cannot be converted to List< ? extends MyEntity>
关于泛型的 Java 课程正在引导我出现方差概念.这让我有些头疼,因为我无法找到它的简单演示.
我已经在stackoverflow上阅读了几个类似的问题,但我发现它们对于Java学习者来说太难理解了.实际上问题在于对泛型的解释需要理解方差,并且证明了方差的概念在很大程度上依赖于泛型理解.
这个标题让我想起了学习广义相对论的日子. - CR 13年12月22日7:34
四个理论问题让我很困惑,我找不到好的和简单的解释.在这里他们是,我目前的部分理解(我担心专家将非常有乐趣阅读这个).
欢迎您提供纠正和澄清的帮助(请记住,这适用于初学者,而不是专家).
关于带有列表的泛型有界类型,我遇到了一个小问题.请帮忙!
Model.java
public class Model {
}
Run Code Online (Sandbox Code Playgroud)
ClassA.java
public class ClassA<T extends Model> {
private List<T> models;
public ClassA() {
models.add((T) new Model());
}
}
Run Code Online (Sandbox Code Playgroud)
它在这一行给我一个从模型到T警告的未经检查的强制转换:
models.add((T) new Model());
Run Code Online (Sandbox Code Playgroud)
我知道我收到了这个警告,因为我可以安全地从一个子类投射到一个超级类而不是反过来.
有没有办法解决这个问题,还是我可以安全地压制警告?
我正在调用一个io.netty.bootstrap.BootStrap具有以下签名的java方法:
public <T> B option(ChannelOption<T> option, T value)
Run Code Online (Sandbox Code Playgroud)
我使用以下代码来调用此方法:
b.option(ChannelOption.SO_KEEPALIVE, true);
Run Code Online (Sandbox Code Playgroud)
这无法编译,出现以下错误:
Error:(57, 30) type mismatch;
found : io.netty.channel.ChannelOption[Boolean]
required: io.netty.channel.ChannelOption[Any]
Note: Boolean <: Any, but Java-defined class ChannelOption is invariant in type T.
You may wish to investigate a wildcard type such as `_ <: Any`. (SLS 3.2.10)
b.option(ChannelOption.SO_KEEPALIVE, true); // (4)
^
Run Code Online (Sandbox Code Playgroud)
我不完全理解这说的是什么,但我理解它抱怨得到一个布尔值,因为它是参数化
Any而不是Boolean.所以我尝试了以下代码,它的工作原理:
b.option(ChannelOption.SO_KEEPALIVE, Boolean.box(true));
Run Code Online (Sandbox Code Playgroud)
这编译和工作.有没有办法让这个更漂亮没有box电话?
有人可以翻译那个编译错误吗?
谢谢.
我对协方差和相反性有些困惑。我们是否说过,在Java中,当我们使用时通常是矛盾的? super X。
现在阅读我的书,我理解了以下概念:
这是矛盾的:
method(Predicate<? super X> pred)
Run Code Online (Sandbox Code Playgroud)
但这是协变的:
method(List<? super X> list) //And then we use add for a list of course
Run Code Online (Sandbox Code Playgroud)
这个概念没有明确地写成我要问你的方式,所以我想知道,这个定义正确吗?如果是,为什么第一个是协变的,为什么最后一个是协变的(如果两者都使用super关键字)?
我的印象是,Scala列表中的每个对象必须具有相同的类型,如果我们需要具有不同类型的集合,则应使用元组.
从Scala的文档来看,List是
用于表示类型元素的有序集合的不可变链表的类.
scala> val l1 = List(1,2,3)
l1: List[Int] = List(1, 2, 3)
scala> val l1 = List(1,2,3, "oh really?!")
l1: List[Any] = List(1, 2, 3, oh really?!)
Run Code Online (Sandbox Code Playgroud)
似乎并非如此.毕竟Any它本身是一个有效的Scala类型,一切都可以减少到它.
请澄清
java ×7
generics ×5
covariance ×4
inheritance ×3
java-8 ×2
list ×2
scala ×2
c# ×1
c#-4.0 ×1
java-7 ×1
java-stream ×1
lambda ×1
polymorphism ×1
types ×1