Java学习笔记技术干货

Java泛型详解

2016-12-22  本文已影响750人  向日花开

泛型

泛型由来

泛型字面意思不知道是什么类型,但又好像什么类型都是。看前面用到的集合都有泛型的影子。

    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    ...
    }

以ArrayList为例,它为什么要写成ArrayList<E>这样.我也不知道他为什么要写成这样,但是我知道如果它不用泛型,那代码就乱了,那也别写代码了。

假如我要写一个类存放一个int类型的模型,那简单
       public class IntegerFun {
         private int data;

           public int getData() {
               return data;
           }

           public void setData(int data) {
               this.data = data;
           }
       }
满足你的需求,但需求变了,我还要一个存放String类型的,那你也忍了,再来一个
      public class StringFun {

          private String data;

          public String getData() {
              return data;
          }

          public void setData(String data) {
              this.data = data;
          }
      }
需求又添加了一个,存放Long、Student、Math.....于是撕逼开始...结束之后,这次你聪明了,写了一个万能的,管它存放什么都行的类:
    public class ObjectFun {
        private Object data;

        public Object getData() {
            return data;
        }

        public void setData(Object data) {
            this.data = data;
        }
    }

这样总算解决了问题,看用法:



你总觉得你写的前无故人,后无来者了,可是经理还是过来找你了,因为你的程序跑不起来了,你认真的看了一下,发现代码第十五行,存放的是Integer 结果你转成了Float出错了,那你可能会抱怨编译器
没有立即告诉你这里存在问题,接下来我们来看看运用泛型会怎么样。

    public class Fun<T> {
        private T data;

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }
    }
用法:
这就是使用泛型的原因.

多泛型

上面写的还不够全,因为Fun<T>只能存放一种类型的元素,假如我要存放多种呢,我希望你已经会了,再来一个泛型。
  /**
   * 泛型类
   *
   * @param <T>泛型T
   * @param <V>泛型V
   */
  public class Fun<T, V> {
      private T data;
      private V data2;

      //泛型方法
      public T getData() {
          return data;
      }

      public void setData(T data) {
          this.data = data;
      }

      public V getData2() {
          return data2;
      }

      public void setData2(V data2) {
          this.data2 = data2;
      }
  }
要存放无数个呢.....
Fun<T,T1,T2,T3,.,.>{
}

泛型规范

T1,T2,T3,.......泛型可以随便写吗,可以随便写,但我们追求规范。

泛型接口,泛型类,泛型方法

案例运行
     public class Demo {

         public static void main(String[] args) {
             Manager<Student> manager = new Manager<Student>();
             manager.add(new Student("小鱼", 20));
             manager.add(new Student("小黑", 30));
             manager.add(new Student("SF", 21));

             System.out.println("get--->" + manager.get(1));

             manager.sop();
         }
     }
泛型能代表的太多了,是否能给它一些限制呢,答案也是肯定的。下面来看泛型的上下限。

确定上限

什么叫确定上限,字面意思就是你的上限我已经给你定好了,你不可能再超出这个范围,那就有用到一个关键字 extends,我们让 T(泛型)extends 某一个类,那是不是这个泛型的上限就被你决定了。
下面我们看代码。

确定下限

感觉用的不多,关键字 super

案例

    public class Demo {
        public static void main(String[] args) {
            Collection<Student> cs = new ArrayList<Student>();
            cs.add(new Student("李xx", 20));
            cs.add(new Student("xxx", 19));
            cs.add(new Student("hhahah", 20));
            sop2(cs);

        }

        //接收的引用类型要么是Student类,要么是Student的父类:  确定下限
        static void sop2(Collection<? super Student> cs) {
            Iterator<?> iterator = cs.iterator();
            while (iterator.hasNext()) {
                System.out.println(iterator.next());
            }
        }
    }

让我们带着泛型的目光回顾 TreeSet中涉及Collections、Comparator、Comparable

我们说过TreeSet存储的元素是要支持可排序的,那他有两种方式,一是实现Comparable接口,二是在构造TreeSet实例的时候传一个Comparator实例。
我们先看源码:

这就是Comparable所有的代码,简单吧.

和Comparable很像;

当初也许你会很好奇,这个类凭什么帮你排序,现在你知道了吧,你所传的实例都被泛型限定好了,这里出现了一个以前没说过的"?"号,我们先忽略它。
两个sort方法,要么实现Comparable,要么是Comparator,但有一点他们是统一的,就是都是用确定下限的泛型方式。加深印象!

案例 Comparator泛型的确定下限

还有一个?号等着去解决...

? 通配符

我们在Collections 的源码中看到了好多Comparable<? super T>,那这个?和T有什么关系呢。

? 和T没有什么必然的联系。我们要使用T,则必须在定义类的时候申明T,像 class Fun<T>,然后在类里可以使用T这一类型,
而?则表示通配(填充),表示通配,表示通配,而不是定义,因此我们使用之前不用定义它,表示通配!就如 Class<?> cls = Person.class.getClass();
Class<T>在实例化的时候,T要替换成具体类
Class<?>它是个通配泛型,?可以代表任何类型

<? extends T>受限统配,表示T的一个未知子类。
<? super T>下限统配,表示T的一个未知父类。

参考

夯实JAVA基本之一 —— 泛型详解(1)(2):基本使用
计算机思维逻辑-泛型 (上)(中)(下)

上一篇下一篇

猜你喜欢

热点阅读