烟台Java培训
达内烟台中心

15265420612

热门课程

java泛型内各种参数的异同分析

  • 时间:2016-09-18
  • 发布:烟台ava培训
  • 来源:烟台ava培训

一、 List 与 List 之间为什么是非继承关系。

我认为以下两个原因可以解释这个问题:

1、Java中泛型是后来引入的特性,为了兼容之前的代码,泛型是存在擦除机制的,List 与 List 在擦除后的class中均为List,并不存在继承关系。

2、从逻辑上解释不能有继承关系的原因:

1 public void test(List list) {

2    list.add(new Orange());

3    }

在上面的代码中,test方法接收一个List 类型的list,并在此list 中插入了一个Orange对象,这个方法是没有任何问题的。现在假设List 与 List 间存在继承关系,那么此方法可以接收一个List 类型的list 参数作为方法的参数,然而之后在方法中就会在一个声明是List 的list 中插入一个 Orange 对象,这显然是不符合逻辑的。所以 List 与 List 之间应该是非继承关系。

二、 List 存在的必要性。

由一的介绍我们可以知道 test 方法只能只能接受 List 而不能接受 List 类型的 list, 现在我想写一个方法,既能接受List 又能接收 List 类型的 List,应该怎么做呢? 这时就要用到 List 来实现这个功能了。

List 表示此 list持有的对象类型是 Fruit 或者从 Fruit 导出的类型(Apple 或者 Orange),相当于为 List 持有的对象类型规定了一个上界。

我们只需将上面的test 方法改为 :

1 public class TestGen {

2

3 public void test(List list) {

4 /*由于传入的参数是 List 参数的list,这个list是不能进行add 操作的。

5 list.add(new Fruit());

6 list.add(new Orange());

7 list.add(new Apple());*/

8 }

9

10 public static void main(String[] args) {

11

12 List list = new ArrayList();

13 List list1 = new ArrayList();

14 List list2 = new ArrayList();

15

16 TestGen tg = new TestGen();

17

18 tg.test(list);

19 tg.test(list1);

20 tg.test(list2);

21

22 }

23 }

现在test 方法里的参数 变为了 List list, 在 main 方法里可以看到此方法可以接受 List,List,List多种类型的 list,实现了我们想要的功能。

但是在上述代码的 test 方法当中我们也可以看到,作为参数传入的 list 是不能进行 add 操作的,无论 add 的是什么类型,这是为什么呢?

原来由于传入的 List 类型是 List list, 在JDK源码中可以看到 List的 add 方法的泛型参数就变为了 ,编译器并不能了解这里需要 add 的是哪个具体子类型,因此它

不会接受任何类型的Fruit,编译器将直接拒绝对参数列表中涉及通配符的方法的调用。

那么我们怎么才能做到向含有通配符的泛型限制的list 中做插入操作呢? 这时我们就要用到 参数。

三、List 与 List 的区别及 List 存在的必要性。

由二可知, 要想向含有通配符的泛型限制的list 中做插入操作, 此泛型限制必须为 。 前面已经说到,List 为此List 可以持有的对象类型规定了一个上

界,即持有的对象只能为 Fruit 或 Fruit 的子类型。 相应地, List 则为 List 可以持有的对象类型规定了一个下界,即持有的对象只能为 Fruit 或 Fruit 的超类。

因此若将 test 方法改为下面这样,则 add 操作可以进行。

1 public void test(List list) {

2 list.add(new Fruit());

3 list.add(new Orange());

4 list.add(new Apple());

5 }

因为我们可以确定 传入 test 方法的参数至少也是一个 持有 Fruit 类型的 List,所以我们向此 list 中加入 Fruit 及Fruit 的子类型的对象是没有任何问题的。

四、 与 区别。

两个东西应用的场景是不同的,作用于方法或者类上,而 则不可以。下面举例说明。

1 public class TestGen {

2 private T value;

3

4 public TestGen(T value) {

5 this.value = value;

6 }

7

8 public T getValue() {

9 return value;

10 }

11

12 public void setValue(T value) {

13 this.value = value;

14 }

15

16 public void test1(E e) {

17 System.out.println(e.getClass().getName());

18 }

19

20 public static void main(String[] args) {

21

22 TestGen tg = new TestGen(new Fruit());

23 //由于 setValue 方法参数列表中涉及通配符(setValue方法中的 T 相当于 ? extends Fruit),setValue方法不能调用。

24 //tg.setValue(new Fruit());

25

26 tg.test1(new Fruit());

27 //tg.test1(new Object()); Object并不是Fruit的子类型,并不能作为参数传入test1方法。

28 }

29 }

在代码中可以看到,类上的限定 及方法上的限定 使得类和方法能接受的类型均为 Fruit 及 Fruit 的子类型。

五、原生List 与 List 区别。

无界通配符 ? 与 原生类型看似好像是等价的,但无界通配符可以有以下含义:“我是想用Java的泛型来编写这段代码,我在这里并不是要用原生类型,但是在当前这种情况下,泛型参数可以持有任何类型”。

使用无界通配符的 List 要比 原生 List 要安全些。 在原生 list 中,我们可以随意进行插入操作,可以向同一个 list 中既插入 object 对象,又插入 Fruit,Apple 对象,而 List 是不允许进行 add 操作的。

六、解释自限定泛型 class A>{ }。

在 Java 泛型中,这算是一种经常出现的惯用法,这种用法意味着 基类 (这里的类A) 使用其导出类代替其参数,泛型基类变成了一种其所有导出类的公共公能的模板,但是这些功能对于其所有参数和返回值,将使用导出类型。

下面举例说明。

1 class A > {

2 void set(T arg) {

3 System.out.println("in A");

4 }

5 }

6 //泛型基类变成了一种其所有导出类的公共公能的模板

7 //导出类B和C均可调用基类的set方法,且只接受导出类对应的类型

8 class B extends A {

9

10 }

11 class C extends A {

12

13 }

14 public class TestGen {

15 void test2(B b1, B b2, C c1, A a1) {

16 b1.set(b2);

17 //使用自限定泛型时,在导出类中调用的set方法只接受对应的导出类型,不接受基类型和其他的导出类型

18 //b1.set(c1); 不接受其他的导出类型

19 //b1.set(a1); 不接受基类型,编译器不能识别将类型传递给set的尝试,因为没有任何方法有这样的

20 //签名,实际上,这个参数已经被覆盖

21 }

22 }

上一篇:烟台达内java培训班学员感言
下一篇:Java语言有可能代替C语言吗
选择城市和中心
贵州省

广西省

海南省

达内教育

有位老师想和您聊一聊