zoukankan      html  css  js  c++  java
  • 泛型、通配符

    泛型
    回顾泛型类
    泛型类:具有一个或多个泛型变量的类被称之为泛型类。
    public class A<T> {
        private T t;
        public A(T t) {
            this.t = t;
    }
    public T get() {
        return t;
    }
    }


    2 泛型方法
    泛型方法的特点:
    方法的参数中会使用泛型变量;
    方法的返回值中会使用泛型变量。

    public <T> T get(T[] ts) {
      return ts[ts.lengt / 2];
    }
    String[] names ={“zhangSan”, “liSo”, “wangWu”};
    String name = get(names);


      调用泛型方法时无需指定泛型变量,编译器会通过实际参数的类型来识别泛型变量的类型,上例中传递的参数为String[]类型,那么相当于给泛型类型T赋值为String。

    3 继承(实现)泛型类(接口)
    继承泛型类需要为父类的泛型变量赋值!就好比创建泛型类的对象时需要给泛型变量赋值一样。
    // 创建泛型类对象
    List<String> list = new ArrayList<String>();
    // 继承泛型类1:子类也是泛型类
    public class MyList1<T> extends ArrayList<T> {
     …
    }
    // 继承泛型类2:子类不是泛型类
    public class MyList2 extends ArrayList<String> {
      …
    }


    4 通配符
    为了说明通配符的作用,我们先看个例子:
    List<Object> list1 = new ArrayList<String>();
    List<Object> list2 = new ArrayList<Integer>();


    上面的调用都是编译不通过的!
    这说明想写一个即可以打印list1,又可以打印list2的方法是不可能的!

    public static void fun(List<Object> list) {…}
    List<String> list1 = new ArrayList<String>();
    List<Integer> list2 = new ArrayList<Integer>();
    fun(list1);//编译不通过
    fun(list2);//编译不通过


    如果把fun()方法的泛型参数去除,那么就OK了。即不使用泛型!

    public static void fun(List list) {…}//会有一个警告
    List<String> list1 = new ArrayList<String>();
    List<Integer> list2 = new ArrayList<Integer>();
    fun(list1);
    fun(list2);


    上面代码是没有错了,但会有一个警告。警告的原因是你没有使用泛型!Java希望大家都去使用泛型。
    你可能会说,这里TMD根本就不能使用泛型。

    4.1 通配符概述
    通配符就是专门处理这一问题的。

    public static void fun(List<?> list) {…}


    上面代码中的“?”就是一个通配符,它只能在“<>”中使用。造成不能把它从“<>”中拿出来。
    这时你可以向fun()方法传递List<String>、List<Integer>类型的参数了。当传递List<String>类型的参数时,表示给“?”赋值为String;当传递List<Integer>类型的参数给fun()方法时,表示给“?”赋值为Integer。

    4.2 通配符的缺点
      带有通配符的参数不能使用与泛型相关的方法,例如:list.add(“hello”)编译不通过。
    上面的问题是处理了,但通配符也有它的缺点。
    在上面例子中,List<?> list参数中的通配符可以被赋任何值,但同时你也不知道通配符被赋了什么值。
    当你不知道“?”是什么时,会使你不能使用任何与泛型相关的方法。也就是说fun()方法的参数list不能再使用它的与泛型相关的方法了。例如:list.add(“hello”)是错误的,因为List类的add()方法的参数是T类型,而现在你不知道T是什么类型,你怎么去添加String的东西给list呢?如果使用者在调用fun()方法时传递的不是List<String>,而是List<Integer>时,你添加String当然是不可以的。

    当然,还可以调用list的get()方法。就算你不知道“?”是什么类型,但它肯定是Object类型的。所以你可以:Object o = list.get(0);

    4.3 通配符的限制
      通配符只能出现在引用的定义中,而不能出现在创建对象中。例如:new ArrayList<?>(),这是不可以的。ArrayList<?> list = null,这是可以的。

    4.4 带有下边界的通配符
    List<? extends Number> list;
    其中<? extends Number>表示通配符的下边界,即“?”只能被赋值为Number或其子类型。

    public static void fun(List<? extends Number> list) {…}
    fun(new ArrayList<Integer>());//ok
    fun(new ArrayList<Double>());//ok
    fun(new ArrayList<String>());//不ok


    当fun()方法的参数为List<? extends Number>后,说明你只能赋值给“?”Number或Number的子类型。
    虽然这多了一个限制,但也有好处,因为你可以list的get()方法了。就算你不知道“?”是什么类型,但你知道它一定是Number或Number的子类型。所以:Number num = list.get(0)是可以的。
    但是,还是不能调用list.add()方法!

    4.5 带有下边界的通配符
    List<? super Integer> list;
    其中<? super Integer>表示通配符的下边界,即“?”只能被赋值为Integer或其父类型。

    public static void fun(List<? super Integer> list) {…}
    fun(new ArrayList<Integer>());//ok
    fun(new ArrayList<Number>());//ok
    fun(new ArrayList<Object>());//ok
    fun(new ArrayList<String>());//不ok


    这时再去调用list.get()方法还是只能使用Object类型来接收:Object o = list.get(0)。因为你不知道“?”到底是Integer的哪个父类。
    但是你可以调用list.add()方法了,例如:list.add(new Integer(100))是正确的。因为无论“?”是Integer、Number、Object,list.add(new Integer(100))都是正确的。

    4.6 通配符小结
    1. 方法参数带有通配符会更加通用;
    2. 带有通配符类型的对象,被限制了与泛型相关方法的使用;
    3. 下边界通配符:可以使用返回值为泛型变量的方法;
    4. 上边界通配符:可以使用参数为泛型变量的方法。

    5 泛型父类获取子类传递的类型参数
    看一个例子:
    public class A<T> {
    }
    pubilc class B extends A<String> {
    }
    public class C extends A<Integer> {
    }


    如果你需要在A类中得到子类给T赋值的类型,那么可以使用下面的方法:
    public class A<T> {
      public A() {
        ParameterizedType pType = (ParameterizedType)this.getClass().getGenericSuperclass();
        Class clazz = (Class)pType.getActualTypeArguments()[0];
        System.out.println(clazz.getName());
    }
    }

  • 相关阅读:
    flink 读取kafka 数据,partition分配
    Flink 报错 "Could not find a suitable table factory for 'org.apache.flink.table.factories.StreamTableSourceFactory' in the classpath"
    flume接收http请求,并将数据写到kafka
    【翻译】Flume 1.8.0 User Guide(用户指南) Processors
    【翻译】Flume 1.8.0 User Guide(用户指南) Channel
    【翻译】Flume 1.8.0 User Guide(用户指南) Sink
    【翻译】Flume 1.8.0 User Guide(用户指南) source
    【翻译】Flume 1.8.0 User Guide(用户指南)
    Apache Flink 简单安装
    Java之使用IDE
  • 原文地址:https://www.cnblogs.com/cyf18/p/14315992.html
Copyright © 2011-2022 走看看