Java泛型详解

泛型

泛型由来

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

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

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

  • ArrayList运用泛型可以这么写

        ArrayList strings = new ArrayList<>();//可以存String
        ArrayList integers = new ArrayList<>();//可以存Integer类型
        ArrayList objects = new ArrayList<>();//可以存对象
      
      
  • ArrayList没用泛型之后:

    如果要存放各种各样的样类型,是不是意味着写各种各样对象的链表,那开发者可以不用活了...咦,或者你可以可不用死了,你发现所有类都继承自Object类,那只要这么写一个

    在取出元素的时候强转成对应的类型就可以了,是的,这样就可以不会被写代码累死了。但为什么源码没有这么写,因为它没泛型强大!让我们看下面代码了解泛型的由来。

  • 假如我要写一个类存放一个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;
            }
        }
    

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


    Java泛型详解_第1张图片

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

        public class Fun {
            private T data;
    
            public T getData() {
                return data;
            }
    
            public void setData(T data) {
                this.data = data;
            }
        }
    
    用法:
    Java泛型详解_第2张图片
    这就是使用泛型的原因.

    多泛型

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

    泛型规范

    T1,T2,T3,.......泛型可以随便写吗,可以随便写,但我们追求规范。
    • E — Element,常用在java Collection里,如:List,Iterator,Set
    • K,V — Key,Value,代表Map的键值对
    • N — Number,数字
    • T — Type,类型,如String,Integer等等

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

    • 泛型接口

        /**
         * 格式:接口名后面跟 
         *
         * @param 
         */
        public interface IManager {
            void add(T data);
      
            T remove(int index);
      
            void sop();
        }
      
    • 泛型类(之前的都是)

    • 泛型类实现泛型接口(关于怎么更好的构建泛型类,就靠诸君在日后的生涯中寻找答案了)

        /**
         * @param 
         */
        public class Manager implements IManager {
            private List datas;
      
            public Manager() {
                datas = new ArrayList<>();
            }
      
            @Override
            public void add(T data) {
                datas.add(data);
            }
      
            @Override
            public T get(int index) {
                return datas.get(index);
            }
      
            @Override
            public void sop() {
                for (T t : datas) {
                    System.out.println(t);
                }
            }
        }
      
    • 泛型方法(前面的好多)

           @Override
            public T get(int index) {
                 return datas.get(index);
            }
      
            //泛型方法
             public T getData() {
                 return data;
             }
      
    案例运行
         public class Demo {
    
             public static void main(String[] args) {
                 Manager manager = new Manager();
                 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 某一个类,那是不是这个泛型的上限就被你决定了。
    下面我们看代码。

    • 定义基类

           /**
            * 基类
            */
           public class Person {
      
           int age;
           String name;
      
           public Person(String name, int age) {
               this.name = name;
               this.age = age;
           }
       }
      
    • 定义子类

        public class Child extends Person {
      
            public Child(String name, int age) {
                super(name, age);
            }
        }
      
    • 还有一个不相关的类

           public class Dog {
      
               private String name;
               private int age;
      
               public Dog(String name, int age) {
                   this.name = name;
                   this.age = age;
               }
           }
      
    • 定义泛型类

          public class Fun1 {//确定上限,(泛型类的建模很重要)
              private T datas;
      
              public T getDatas() {
                  return datas;
              }
      
              public void setDatas(T datas) {
                  this.datas = datas;
              }
          }
      
    • 运行(接收的引用类型要么是Person类,要么是Person的子类: 确定上限)


      Java泛型详解_第3张图片

    确定下限

    感觉用的不多,关键字 super

    案例

        public class Demo {
            public static void main(String[] args) {
                Collection cs = new ArrayList();
                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 cs) {
                Iterator iterator = cs.iterator();
                while (iterator.hasNext()) {
                    System.out.println(iterator.next());
                }
            }
        }
    

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

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

    • Comparable

       package java.lang;
      
       public interface Comparable {//一个泛型接口
           int compareTo(T var1);
       }
      

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

    • Comparator代码巨多,我们也就只看一行

        public interface Comparator {
            int compare(T var1, T var2);
            ......
         }
      

    和Comparable很像;

    • Collections集合工具类,代码巨多,我们也就只看几行

         public static > void sort(List var0) {
                 var0.sort((Comparator)null);
             }
      
         public static  void sort(List var0, Comparator var1) {
              var0.sort(var1);
            }
      

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

    案例 Comparator泛型的确定下限

    • Animal(基类)

        public class Animal {
             int age;
             String name;
      
            public Animal(int age, String name) {
                this.age = age;
                this.name = name;
            }
      
            @Override
            public String toString() {
                return "[" + this.name + "\t" + this.age + "]";
            }
        }
      
    • Cat(子类)

        public class Cat extends Animal {
      
            public Cat(int age, String name) {
                super(age, name);
            }
      
            @Override
            public String toString() {
                return super.age + "";
            }
        }
      
    • 运行


      Java泛型详解_第4张图片
    还有一个?号等着去解决...

    ? 通配符

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

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

    参考

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

    你可能感兴趣的:(Java泛型详解)