泛型超级与扩展

时间:2012-10-30 06:22:57

标签: java generics scjp generic-type-argument

就在我认为我终于理解了泛型的时候,我遇到了以下例子:

public class Organic<E> {
          void react(E e) { }
          static void main(String[] args) {
            //1: Organic<? extends Organic> compound = new Aliphatic<Organic>(); 
            //2: Organic<? super Aliphatic> compound = new Aliphatic<Organic>(); 
           compound.react(new Organic());
           compound.react(new Aliphatic());
           compound.react(new Hexane());
 } }
 class Aliphatic<F> extends Organic<F> { }
 class Hexane<G> extends Aliphatic<G> { }

它说,如果第1行被取消注释,则以下内容将无法编译:

  compound.react(new Organic());  
  compound.react(new Aliphatic());  
  compound.react(new Hexane());

如果第2行被注销,则以下内容将无法编译:

compound.react(new Organic());

在第二个例子中,允许脂肪族和它的超类型。那么为什么不允许脂肪族?

在第一个例子中,为什么不允许new Organic

第一个编译器错误:

- The method react(capture#1-of ? extends Organic) in the type Organic<capture#1-of ? extends Organic> is not applicable for the arguments (Organic)
- The method react(capture#2-of ? extends Organic) in the type Organic<capture#2-of ? extends Organic> is not applicable for the arguments (Aliphatic)
- The method react(capture#3-of ? extends Organic) in the type Organic<capture#3-of ? extends Organic> is not applicable for the arguments (Hexane)

第二次编译错误:

- The method react(capture#1-of ? super Aliphatic) in the type Organic<capture#1-of ? super Aliphatic> is not applicable for the arguments  (Organic)

4 个答案:

答案 0 :(得分:5)

您的第一份声明

Organic<? extends Organic> compound

表示compound 可以成为Organic<SomeSubtypeOfHexane>(因为Aliphatic延伸OrganicHexane延伸AliphaticSomeSubtypeOfHexane延伸Hexane)。

在这种情况下,compound.react(new Organic())compound.react(new Aliphatic())compound.react(new Hexane())会导致类型错误,因为E中的compound必须是SomeSubtypeOfHexane (或其子类型)。


你的第二个声明

Organic<? super Aliphatic> compound

表示compount 可能Organic<Aliphatic>

在这种情况下,compound.react(new Organic())会导致类型错误,因为E必须是Aliphatic(或其子类型)。


请记住,使用A<? extends B>A<? super B>

声明变量
  • 扩展可分配给它的对象数量,因此,
  • 限制可以对变量执行的操作。

由于类的确切类型未知(仅知道约束),编译器必须在安全方面犯错,并且禁止某些不是共变或逆变的操作。 (如果您还不熟悉它,Co- and contravariance是这些类型泛型的科学背景。)

答案 1 :(得分:2)

主题问题也在其他几个地方讨论过:

从上一次测试(问题34)开始,Java certificate preparation实际上是书中的问题。准备书基于lessons book

即使在这里和其他链接下的解释和书中的写作,解决方案对我来说也不清楚,因为解释主要基于列表界面并且阅读我认为它是一些内部集合特定的解决方案。

但如果您在一侧看到列表界面和添加 - 方法的定义,并且有机类及其<强>反应 - 方法另一方面你会注意到它们是以类似的方式定义的。

public interface List<E> extends Collection<E> {
   ...
   boolean add(E e);
   ...
}

public class Organic<E> {
    ...
    void react(E e) { }
   ...
}                                               

因此,基于List接口示例的所有解释都可以在任何地方找到,也适用于此问题。

List<? extends String> list1 = new ArrayList<String>();
List<? super String> list2 = new ArrayList<String>();
list1.add(new String()); //The method add(capture#1-of ? extends String) in the type List<capture#1-of ? extends String> is not applicable for the arguments (String) - // compile-time error
list2.add(new Object()); //The method add(capture#2-of ? super String) in the type List<capture#2-of ? super String> is not applicable for the arguments (Object) - // compile-time error

看看关于这个的解释:

答案 2 :(得分:1)

我认为你误解了你在react()方法中设置的参数

尝试更改

void react(E e) { }

void react(Organic<E> e) { }

看到差异。您正在寻找对象:Organic<E> Aliphetic<E> Hexane<E>

Organic<E>不是E

并非Aliphetic<E>E

并非Hexane<E>E

答案 3 :(得分:0)

你做了一些混合。
Organic<E>的类型与Organic相同。
您无法执行左new Organic()); 您必须至少考虑执行
new Organic<Object>()); 这只是我能想到的一个编译错误 这当然对您的其他对象实例有效。