精华内容
参与话题
问答
  • 泛型 通配符

    2009-09-13 17:28:49
    求解,为什么不能向fruit里面添加任何对象了呢? [code="java"] class ListGenertics{ public static void main(String...... List<? extends Fruit> fruit=new ArrayList();...现在似乎弄明白些了...
  • 泛型通配符

    2015-11-25 21:53:50
    通配符泛型  为了解决类型不能动态根据实例来确定的缺点,引入了“通配符泛型”,使得一个参数可以用来表示一组实例化后的模板。 其中, “?”代表未知类型 extends关键字声明了类型的上界,表示参数化...

    通配符泛型

        为了解决类型不能动态根据实例来确定的缺点,引入了“通配符泛型”,使得一个参数可以用来表示一组实例化后的模板。

    其中,

    “?”代表未知类型

    extends关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类

    super关键字声明了类型的下界,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object

    上界

    [java] view plaincopy
    1. public void upperBound(List<? extends Date> list, Date date)    
    2. {    
    3.     Date now = list.get(0);    
    4.     System.out.println("now==>" + now);    
    5.     //list.add(date); //这句话无法编译    
    6.     list.add(null);//这句可以编译,因为null没有类型信息    
    7. }  
     

     

    无法编译的原因就在于,实际调用时传入的list可能是java.util.Date的某个子类的参数化类型,如: 

     

    [java] view plaincopy
    1. public void testUpperBound()    
    2. {    
    3.     List<Timestamp> list = new ArrayList<Timestamp>();    
    4.     Date date = new Date();    
    5.     upperBound(list,date);    
    6. }  
     

     

         也就是说,upperBound方法中实际的list是List<Timestamp>,向它添加一个基类Date类型,由于基类无法转换为子类,所以无法添加。相反,读取数据时,不管实际的list是什么类型,但可以知道它至少会返回一个Date类型,所以用foreach,get等没有问题。 

    下界

        先看示例代码:

    [java] view plaincopy
    1. public void lowerBound(List<? super Timestamp> list)    
    2. {    
    3.     Timestamp now = new Timestamp(System.currentTimeMillis());    
    4.     list.add(now);    
    5.     //Timestamp time = list.get(0); //不能编译    
    6. }    
     

     

    不能编译的原因是调用代码可能是这样的:

    [java] view plaincopy
    1. public void testLowerBound()    
    2. {    
    3.     List<Date> list = new ArrayList<Date>();    
    4.     list.add(new Date());    
    5.     lowerBound(list);    
    6. }   
     

        在lowerBound方法中的List<? super Timestamp>表示这个list的参数类型可能是Timestamp或Timestamp的父类,如后面的代码里,实际传入的是一个List<Date>类型。List<Date>中可以添加一个Timestamp对象,但list.get()方法返回的对象类型可能是Date甚至是Object,不能安全的向下转换到Timestamp,也就因此无法编译了。

     

        小结一下就是:上界add方法受限,下界get方法受限

     

    泛型方法

        是否拥有泛型方法,与其所在的类是否泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。如:

    public <T> void f(T x) {}

        使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就像普通方法一样。

     

        最后,需要注意的是,一个static方法,无法访问泛型类的类型参数,因为类还没有实例化,所以,若static方法需要使用泛型能力,必须使其成为泛型方法。

    展开全文
  • 一、泛型通配符 子父类关系: List<String> list1 = new ArrayList<>() List<Object> list2 = new ArrayList<>() list1 = list2//编译错误 List<?> list = null; list = list1; list...

    一、泛型通配符

    子父类关系

    List<String> list1 = new ArrayList<>()
    List<Object> list2 = new ArrayList<>()
    list1 = list2//编译错误
    
    List<?> list = null;
    list = list1;
    list = list2;
    

    结论

    • 虽然泛型参数A B之间有子父类类关系,但G< A>和G< B>之间却没有子父类关系。
    • G<?>是G< A>和G< B>的父类。

    读写问题

    Collection<?> c = new ArrayList<String>();
    c.add(new Object());//编译时错误,因为不知道c元素的类型。
    c.add(null);//任何一个对象的默认值都是null,传进去当然没问题。
    
    List<?> list = null;
    List<String> list3 = new ArrayList<>();
    1ist3.add("AA");
    list3.add("BB");
    list3.add("CC");
    list = list3;
    
    Object o = list.get(0)//虽然返回值是一个未知类型,但它一定是一个Object类型
    

    结论

    • 除了null,都不能写入
    • 可以读出

    二、有限制的泛型通配符

    • 上限extends:使用时指定的类型必须是继承某个类,或者实现某个接口,即<=
      通配符指定下限
    • 下限super: 使用时指定的类型不能小于操作的类,即>=
    • 举例: .
      • <? extends Number> ,(无穷小, Number],只允许泛型为Number及Number子类的引用调用
      • <? super Number> ,[Number ,无穷大),只允许泛型为Number及Number父类的引用调用
      • <? extends Comparable> ,只允许泛型为实现Comparable接口的实现类的引用调用。

    父类

    public class Person {
    }
    

    子类

    public class Student extends Person{
    }
    

    测试

    @Test
        public void test1(){
            List<? extends Person> list1 = null;//  <=
            List<? super Person> list2 = null;//  >=
    
            List<Student> list3 = new ArrayList<>();
            List<Person> list4 = new ArrayList<>();
            List<Object> list5 = new ArrayList<>();
    
            list1 = list3;
            list1 = list4;
    //      list1 = list5;//编译时错误
    
    //      list2 = list3;//编译时错误
            list2 = list4;
            list2 = list5;
    
            //读取数据:看右边的定义 <=
            list1 = list3;
            Object o = list1.get(0);
            Person p = list1.get(0);
    //      Student s = list1.get(0);可能比student还小,用student就装不下了
    
            list2 = list4;
            Object o1 = list2.get(0);
    //      Person obj = list2.get(0);可能比Person还大,用Person就装不下了
    
            //写入数据:非null数据
    //      list1.add(new Student());//编译时错误,<= Person,list1可能Student还小
    //      list2.add(new Object());//编译时错误,>= Person,list2可能位于Person和Object之间
    
            list2.add(new Person());
            list2.add(new Student());
        }
    
    展开全文

空空如也

1 2 3 4 5 ... 20
收藏数 3,680
精华内容 1,472
关键字:

泛型通配符