【问题标题】:Lower bounded wildcard下界通配符
【发布时间】:2014-11-29 08:14:26
【问题描述】:

我一直在尝试理解 Java 泛型中下界通配符背后的概念和基本原理。我可以理解上限通配符只读的原因以及它可以在何处以及如何使用。我仍然无法掌握下界通配符。我有一组遵循以下层次结构的类。 (Automobile 是基类。)

Automobile
    - Bus
        - Minibus
        - Doubledecker
        - Electricbus
    - Car
        - Sedan
        - Hatchback
        - Coupe
    - Truck
        - Minivan
        - Pickuptruck
        - Suv
            - Fullsuv
            - Midsuv

现在我正在尝试构建一个(灵活的)列表并向其中添加不同类型的对象。

import java.util.ArrayList;
import java.util.List;

public class Garage {

    public static void main(String[] args)
    {
        List<? super Suv> list = null;

        Suv s = new Suv();
        Truck t = new Truck();
        Automobile a = new Automobile();

        list = new ArrayList<Suv>();
        list.add(s); // declared as List<? super Suv> but actually List<Suv>. No compilation error

        list = new ArrayList<Truck>();
        list.add(t); // declared as List<? super Suv> but actually List<Truck>. Compilation error

        list = new ArrayList<Automobile>();
        list.add(a); // declared as List<? super Suv> but actually List<Automobile>. Compilation error
    }
}

我可以将Suv 的实例添加到List&lt;? super Suv&gt;。但是当我尝试将TruckAutomobile 的实例添加到同一个列表时出现编译错误。 List&lt;? super Suv&gt; 是否不够灵活,无法接受 Suv 或其超类的任何实例? TruckAutomobile 在层次结构树中较高。为什么我无法将这些实例添加到列表中?

【问题讨论】:

    标签: java generics types


    【解决方案1】:

    List&lt;? super Suv&gt; 应该读作“元素类型是Suv 的超类型的列表”

    现在,让我们看看这两行:

    list = new ArrayList<Automobile>();
    list.add(a); // where a is an Automobile
    

    第一行没问题,因为ArrayList&lt;Automobile&gt;确实是“一个元素类型是Suv的超类型的列表”

    但是让我们读出第二行:将一些Automobile 添加到元素类型为Suv 的超类型的列表中。

    就编译器知道的静态类型而言,

    • list 可以指代List&lt;Truck&gt;(因为TruckSuv 的超类型)并且
    • t 可以指代 Car(因为 CarAutomobile

    因此编译器会抱怨以确保您没有将Car 添加到Trucks 的列表中。


    有用的阅读:

    【讨论】:

    • 这是重要的区别:编译器只知道声明的通配符类型list,而不是实际实例化的类型。当该行运行时,它无法执行必要的分析来找到真实类型,部分原因是它不实用,还因为 JLS 不允许这样做。
    • @aioobe 因此,如果我想将卡车或汽车的实例添加到列表中,我是否必须为它们声明特别声明的列表?列表 listOfTrucks;列表 listOfAuto;假设我有一个采用 Suv 或其超类型列表的方法:loadGarage(List super Suv listOfSuv)。由于 listOfSuvs 只接受 Suv 的实例并在我向其中添加 Truck 或 Automobile 时抱怨,我是否应该重载 loadGarage 方法来接受 Truck 和 Automobile ?像 loadGarage(List listOfTruck) 和 loadGarage(List listOfAutomobile)
    • 来自我答案底部的链接:“如果您从参数化容器中获取某些内容,请使用扩展。[...] 如果您将对象放入参数化容器中,请使用 super ." 如果您的loadGarage 方法应该将Automobiles 放入提供的列表中,您应该让该方法接受任何可以存储Automobiles 的列表,即List&lt;? super Automobile&gt;
    猜你喜欢
    • 2021-01-23
    • 1970-01-01
    • 2019-11-01
    • 2019-07-07
    • 1970-01-01
    • 1970-01-01
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多