java泛型上下限

前言:

  java的泛型上下限不是很好理解,尤其像我这种菜鸡。反反复复看了好几遍了...,真是...

一、简单的继承体系

class Person{}

class Student extends Person{}

class Worker extends Person{}

二、泛型上限(extends 关键字)

public static void upperBound(List<? extends Person> list, Person p){
        //正确,因为null没有类型信息
        list.add(null);
        //错误,因为list的参数类型可能是Person的子类
        list.add(p);①
        //成功获取
        if(list.size() > 0){
            Person pp = list.get(0);②
        }
    }

  ①处的错误在于list的参数类型是不确定的,其参数类型可能是 Person的子类,子类集合(List)不能添加父类的元素。测试如下:

public static void testUpperBound(){
        ArrayList<Student> slist =  new ArrayList<Student>();
        Person p = new Person();
        upperBound(slist, p);//无法添加成功
    }

  如何解决泛型上限添加问题,可以使用泛型方法,如下:

public static <T extends Person> void upperBound2(List<T> list, T p){
        list.add(p);
    }
public static void testUpperBound2(){
        ArrayList<Person> plist =  new ArrayList<Person>();
        Person p = new Person();
        Student s = new Student();
        upperBound2(plist, p);

        upperBound2(plist, s);
    }

  也就是说,使用泛型上限add方法时,集合参数类型 和 元素参数类型 要一致,这样添加的时候才不会有矛盾。看一下eclipse中对upperBound2(plist, s);这个函数调用的提示,如下:

  可见,T类型最终会解析为 泛型的最上限类型,Student s相应的向上转型。

  接着说 ② 处,为什么能获取成功呢?泛型上限嘛,至少上限的类型是确定的,所有的上限类型的子类都可以进行向上转型,自然获取是不成问题了。

三、泛型的下限

public static void lowerBound(List<? super Student> list){
        Person var = new Person();
        //错误,list的参数类型可能是 Student,这样就不能添加父类Person了,所以 变量var的类型 必须是 Student或者 Student的子类
        list.add(p);①
        //正确
        Student s = new Student();
        list.add(s);
    }
public static void testlowerBound(){
        ArrayList<Person> list = new ArrayList<Person>();
        lowerBound(list);
    }

  ①处添加失败,告诉我们,泛型下限使用add方法添加元素时,元素的参数类型必须是 下限 或者 下限的子类型。否则会出现子类集合添加父类元素。

public static void lowerBound2(List<? super Person> list){
        Person p = new Person();
        list.add(p);
        //获取,不能编译
        Person as = list.get(0);①
    }
public static void testlowerBound2(){
        ArrayList<Person> list = new ArrayList<Person>();
        lowerBound2(list);
    }

  ①处获取失败了,我们看一下eclipse提示我们该怎么办?

  将 第二个方法 将"as"的类型更改为"Object"  和 泛型的下限 结合一下考虑一下,add(e)方法在正确添加后,都会成为Object对象,在使用get(index)方法时,会转换为

? super Person类型(可能是Person类型,也可能是Person的父类类型,甚至是Object),执行Person as = list.get(0),那么就有了 向下转型。java中无法保证向下转型是安全的。所以①处不能编译。

四、泛型上限最常见的一个应用

List<Person> plist = new ArrayList<Person>();
List<Student> slist = new ArrayList<Student>();

plist.addAll(slist);

五、泛型下限最常见的一个应用

Set<Student> set = new TreeSet<Student>(new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        return 0;
    }
});

六、泛型上下限一个综合的例子

  注:个人瞎掰的...,就是将上面两个例子结合在一起!

Set<Person> set = new TreeSet<Person>(new Comparator<Person>() {
    @Override
    public int compare(Person o1, Person o2) {
        return 0;
    }
});
List<Student> slist = new ArrayList<Student>();
List<Worker> wlist = new ArrayList<Worker>();
set.addAll(slist);
set.addAll(wlist);

  接下来,研究一下泛型的擦除...

时间: 2024-10-28 16:16:18

java泛型上下限的相关文章

java 泛型上下限的例子

public static void doGenericExtends(List<? extends Goods> list) { Goods goods = new Goods(); GoodsChild goodsChild = new GoodsChild(); GoodsParent goodsParent = new GoodsParent(); // list.add(goods); compile error // list.add(goodsChild); compile er

java泛型常见面试题

背景:泛型这个知识点平时用的不多,但是在面试的时候很容就被问到,所以还是要准备一些基础的知识储备. 面试旧敌之 Java 泛型 :主要概念及特点 “泛型” 意味着编写的代码可以被不同类型的对象所重用. 泛型是在JDK1.5之后出现的. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 可以看到,使用 Object 来实现通用.不同类型的处理,有这么两个缺点: 每次使用时都需要强制转换成想要的类型 在编译时编译器并不知道类型转换是否正常,运行时才知道,不安全 根据<Java 编程

Java泛型中的PECS原则

今天在写代码的时候使用到了这样一个方法签名: public void foo(Map<String, String> map); 在写这个参数的时候正好在想一些关于泛型的东西,于是: public void foo(Map<? extends String, ? extends String> map); 这两种写法有什么区别呢?记得以前和同学讨论过这个问题,但后来没有记下来,渐渐又淡忘了.今天又去翻了好多资料,总算找到一些可以参考的,赶紧记在这里方便以后温故知新啦.好了,言归正传

Java泛型的协变

在上篇<Java泛型的基本使用>这篇文章中遗留下面问题,即将子类型也能加入到父类型的泛型中.要实现这样的功能必须借助于协变. 实验准备 如今在上篇文章展示的Decorator类型的基础上,添加一些代码,如代码清单1所看到的. 代码清单1 /** * * 描 述:Exp2使用br/> * 作 者:jiaan.gja<br/> * 历 史: (版本号) 作者 时间 凝视 <br/> * @param itemList */ public void doDecorate

2017.4.5 Java 泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型. 泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数. 假定我们有这样一个需求:写一个排序方法,能够对整形数组.字符串数组甚至其他任何类型的数组进行排序,该如何实现? 答案是可以使用 Java 泛型. 使用 Java 泛型的概念,我们可以写一个泛型方法来对一个对象数组排序.然后,调用该泛型方法来对整型数组.浮点数数组.字符串数组等进行排

关于Java泛型的使用

在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Windstep. 原文链接:http://www.cnblogs.com/lwbqqyumidi/p/3837629.html 原文标题:Java总结篇系列:Java泛型 (我的第一篇水文,233)

java 泛型 窜讲

一.为什么使用泛型      复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用.      安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换.这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查. 二.自定义泛型 java中自定义泛型分为三种:泛型类.泛型接口.泛型方法. 下面使用一个案例演示泛型类.泛型方法,泛型接口类似,所以不再演示. // 自定义泛型类publi

1月21日 - (转)Java 泛型

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

Java泛型_上界extends_下界super

?Java泛型_上界extends_下界super ? 通配符类型 <? extends T> 表示类型的上界,表示参数化类型的可能是T或是T的子类 <? super T> 表示类型下界(Java Core中叫超类型限定),表示参数化类型是此类型(T)的超类型(父类型),直至Object 当使用 Upper Bound 通配符时 如下代码, /**  * 代码中通配符<?> 是 <? extends Object> 的简写  *  * @param list