使用通配符的Java集合

使用通配符的Java集合

Java Collections using wildcard

1
2
3
4
5
6
7
public static void main(String[] args) {

    List<? extends Object> mylist = new ArrayList<Object>();

    mylist.add("Java"); // compile error

}

上面的代码不允许您将元素添加到列表中,通配符只能用作方法中的签名,同样不能用于添加,而只能用于访问。
在这种情况下,以上目的是什么?


假设您有一个接口和两个类:

1
2
3
interface IResult {}
class AResult implements IResult {}
class BResult implements IResult {}

然后,您将得到返回结果列表的类:

1
2
3
4
5
6
7
8
9
10
11
12
13
interface ITest<T extends IResult> {
  List< T > getResult();
}

class ATest implements ITest<AResult> {
  // look, overridden!
  List<AResult> getResult();
}

class BTest implements ITest<BResult> {
  // overridden again!
  List<BResult> getResult();
}

当您需要"协变量返回",但是您返回集合而不是自己的对象时,这是一个很好的解决方案。最大的好处是,当独立于ITest接口使用ATest和BTest时,不必强制转换对象。但是,使用ITest接口时,不能将任何东西添加到返回的列表中-无法确定列表真正包含的对象类型!如果允许,则可以将BResult添加到List (作为List <?扩展T>返回),这没有任何意义。

因此,您必须记住以下内容:List <? X>扩展定义了一个可以轻松覆盖的列表,但它是只读的。


约书亚·布洛赫(Joshua Bloch)在他的著作《有效的Java》(第二版)中解释了他所谓的使用泛型的生产者/消费者原则。 Josh的解释应该告诉您为什么您的示例不起作用(编译)...

第5章(泛型)可在此处免费获得:http://java.sun.com/docs/books/effective/generics.pdf

有关此书(和作者)的更多信息,请访问:http://java.sun.com/docs/books/effective/


有界通配符类型的要点是它们在方法签名中的使用,以增加API的灵活性。例如,如果实现了通用Stack,则可以提供一种将多个元素压入堆栈的方法,如下所示:

1
2
3
4
5
public void pushAll(Iterable<? extends E> elements) {
    for(E element : elements){
       push(e);
    }
}

与没有通配符的pushAll(Iterable elements)签名相比,它的优点在于它允许将E的子类型的集合传递给方法-通常不被允许,因为Iterable在某种程度上与直觉相反,不是Iterable的子类。


对于使用通配符的Java泛型,假设只打算从通配符中读取,则可以使用上述声明。

不允许对其进行添加/写入,因为必须在编译时剥离所有泛型类型,并且在编译时,编译器没有办法知道List只是字符串,(它可以是任何对象,包括字符串! )

但是,您可以从中读取内容,因为它们将至少是对象。在Java集合中不允许混合使用不同的类型以保持内容的清洁和可理解,这有助于确保这一点。


Java泛型:集合中的通配符

  • 延伸
  • 今天,我将向您解释通配符的作用。理解这个概念有点困难

    现在,假设您有一个抽象类,并且您有一个名为paintObject()的抽象方法。

    1
    Now you want to use different type of collection in every child class.

    这是AbstractMain方法。

    在这里,我们针对此Abstract Main方法采取的步骤

    1.我们创建了抽象类

    2.在参数中,我们定义了T(您可以使用任何字符)
    -在这种情况下,无论哪个类实现了此方法,它都可以使用任何类型的类。
    例如类可以实现类似的方法
    public void paintObject(ArrayList对象)或public void paintObject(HashSet对象)

    3.并且我们还使用了E扩展MainColorTO
    -在这种情况下E扩展MainColorTo
    -显然这意味着您要使用的任何类都必须是MainColorTo的子类

    4.我们定义了一个抽象方法,称为paintObject(T object,E objectTO)
    -现在无论哪种类都是实现方法,该方法都可以在该方法必须使用MainColorTO类型的第一个参数和第二个参数上使用任何类

    1
    2
    3
    public abstract class AbstractMain<T,E extends MainColorTO> {
          public abstract void paintObject(T Object,E TO);  
    }

    现在我们将扩展到抽象类之上,并在其下实现方法
    例如

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class MainColorTO {  
         public void paintColor(){
               System.out.println("Paint Color........");
         }
      }

    public class RedTO extends MainColorTO {
       @Override
       public void paintColor() {
       System.out.println("RedTO......");
     }
    }
    public class WhiteTO extends MainColorTO {
       @Override
       public void paintColor() {
         System.out.println("White TO......");
       }
     }

    现在我们举两个例子。

    1.PaintHome.java

    1
    2
    3
    4
    5
    6
    7
    public class PaintHome extends AbstractMain<ArrayList, RedTO> {
        @Override
        public void paintObject(ArrayList arrayList,RedTO red) {
            System.out.println(arrayList);

        }
     }

    现在在上面的PaintHome.java中,您可以检查我们是否在第一个参数中使用了ArrayList(因为可以使用任何类),在第二个参数中我们使用了RedTO(正在扩展MainColorTO)

    2,PaintCar.java

    1
    2
    3
    4
    5
    6
    7
    public class PaintCar extends AbstractMain<HashSet, WhiteTO>{
        @Override
        public void paintObject(HashSet Object,WhiteTO white) {
            System.out.println(Object);

        }
     }

    现在在上面的PaintCar.java中,您可以检查我们是否在第一个参数中使用了HashSet(因为我们可以使用任何类),在第二个参数中我们使用了WhiteTO(正在扩展MainColorTO)

    要记住的Ponint
    您不能在课程级别使用super关键字,而只能在课程级别使用extends关键字

    1
    2
    3
    4
    5
    public abstract class AbstractMain<P,E super MainColorTO> {

        public abstract void paintObject(P Object,E TO);

    }

    上面的代码将给您编译器错误。


    List< ? >相同的List<? extends Object>满足了归纳所有类型ListListList等的目的(因此,所有具有正确类型的类型都可以代替?) 。所有这些类型的值都可以分配给类型List< ? >的变量(这与List有所不同!)。

    通常,您不能将字符串添加到此类列表。但是,您可以从列表中读取Object,也可以添加null。您还可以计算列表的长度,等等。这些是可以保证对每种类型都适用的操作。

    有关通配符的良好介绍,请参见论文"将通配符添加到Java编程语言"。这是一篇学术论文,但仍然很容易阅读。


    这有效:

    1
    2
    List<? super Object> mylist = new ArrayList<Object>();
    mylist.add("Java"); // no compile error

    从O'Reilly的Java泛型:

    The Get and Put Principle: use an extends wildcard when you only get values our of a structure, use a super wildcard when you only put values into a structure, and don't use a wildcard you both get and put.


    推荐阅读

      linux克隆代码命令?

      linux克隆代码命令?,系统,代码,文件,命令,目录,源文件,文件夹,路径,目标,表

      linux命令支持通配符?

      linux命令支持通配符?,工具,系统,命令,灵活,较大,名称,名字,环境,数字,文件,L

      linux命令行调试代码?

      linux命令行调试代码?,环境,代码,信息,平台,程序,编辑,版本,步骤,体系结构,

      linux编译源代码命令?

      linux编译源代码命令?,工具,代码,百度,最新,环境,项目,系统,电脑,密码,内核,l

      linux命令提交代码?

      linux命令提交代码?,工作,系统,地址,代码,命令,数据,信息,目录,标准,发行,求

      linux代码同步命令?

      linux代码同步命令?,时间,服务,系统,地址,代码,网络,通信,图片,风险,管理,lin

      linux命令错误代码?

      linux命令错误代码?,系统,密码,电脑,网络,手机,网址,软件,代码,设备,老板,Lin

      linux同步代码命令?

      linux同步代码命令?,时间,系统,通信,网络,标准,图片,服务,代码,线程,单位,Lin

      linux拉取代码命令?

      linux拉取代码命令?,代码,工作,地址,命令,数据,系统,单位,生产,软件,目录,lin

      linux代码对齐命令?

      linux代码对齐命令?,系统,地址,标准,信息,对比,名称,代码,命令,文件,工作,lin

      linux命令运行代码?

      linux命令运行代码?,代码,单位,系统,环境,连续,保险,工具,命令,文件,音乐,Lin

      搭建linux命令行代码?

      搭建linux命令行代码?,系统,软件,工作,名字,服务,代码,地址,环境,管理,密码,l

      linux查看命令代码?

      linux查看命令代码?,系统,信息,代码,名称,命令,设备,数字,第一,软件,管理,在L

      linux删除代码命令行?

      linux删除代码命令行?,系统,代码,命令,文件,不了,环境,档案,名称,目录,文件

      linux命令行代码实现?

      linux命令行代码实现?,标准,代码,管理,网络,地址,工作,命令,网上,环境,名称,

      linux桌面命令代码?

      linux桌面命令代码?,电脑,系统,密码,环境,代码,基础,地址,服务,网上,通讯,lin

      c代码执行linux命令?

      c代码执行linux命令?,系统,工作,标准,情况,代码,环境,设备,命令,函数,指令,li

      linux进入代码行命令?

      linux进入代码行命令?,系统,代码,设备,终端,环境,信息,第一,命令,窗口,模式,

      linux命令行看代码?

      linux命令行看代码?,代码,基础,系统,命令,数字,工作,情况,进程,程序,终端,在L

      linux命令代码怎么看?

      linux命令代码怎么看?,时间,系统,代码,命令,状态,工具,情况,电脑,实时,基础,l