zoukankan      html  css  js  c++  java
  • 泛型技术

    泛型技术的介绍

      这个技术是JDK5中提供的。

      针对集合这类容器而言,它中可以存放任意的对象,当任何的对象存放到集合中之后,都被提升成Object类型,当我们从集合中遍历出每个对象的时候,拿到的都是Object类型,这时如果我们想使用对象自身的功能时,就需要向下转型。只要使用向下转型都可能发生ClassCastException异常

      在给集合中存放对象的时候,以Object形式存放进去的。在取出时也是Object类型,当我们在使用对象的特有方法时,进行向下转型,结果发生了异常。造成这个异常的原因是集合中可以存放任意类型的对象,而在取出的时候,我们并没有对取出的类型做任何的判断,直接把取出的类型转成某种特定的类型。在转的时候,不是这种类型的数据,在强转时就会发生异常。

      集合是个容器,数组也个是容器。可是数组在定义好之后,它的长度固定了,其中存放的数据类型也被固定了。如果给数组中存放类型不匹配的元素,直接在编译时期就报错。

    int[] arr = new int[4];
    arr[0] = 3.14;  //这里直接编译报错。

      数组在定义的时候,就把其中存放的数据类型限定死 了。存放的数据一旦不同就直接编译失败。

      我们现在就把数组这种思想移到集合上,在定义集合的时候,也限定集合中存放的数据类型,那么在真正给集合中存放数据的时候如果类型不一致,直接让编译失败。这种实现就Java给我们提供的泛型技术

    泛型技术的简单应用

      泛型技术:

    • 格式:<具体的类型>  这个类型只能是引用数据类型
    • 作用(解决的问题):把运行时期的问题,提前到了编译时期。可以保证程序在编译通过之后,运行的时候不会再出现问题。
    • 应用:
      • 在API中,只要看到接口,类名等后面使用<变量名> 都是泛型技术;
      • 当我们在使用这些接口,或者类的时候,要使用者类来指定<> 中间的具体类型。
    • 泛型技术在JDK7中升级,升级成菱形技术
      public class GenericDemo2 {
          public static void main(String[] args) {
              //创建TreeSet集合,并且使用泛型技术
              TreeSet<String> set = new TreeSet<String>( new Comparator<String>(){
      
                  public int compare(String o1, String o2) {
                      int temp = o1.length() - o2.length();
                      return temp == 0 ? o1.compareTo(o2) : temp;
                  }
                  
              } );
              
              set.add("aaa");
              set.add("dddd");
              set.add("a");
              set.add("AAA");
              set.add("DDDD");
              set.add("aaa");
              
              for (String obj : set) {
                  System.out.println(obj);
              }
          }
      }

    泛型类、方法、静态方法泛型

      在查阅api的时候发现,api中提供的类上或者接口上应用了泛型技术。oracle公司在设计Java中的这些类的时候,它们在类上,或者接口定义了泛型,那么我们就可以模仿他们,在自己定义类的或者接口的时候,也能够使用泛型技术。

    泛型类

      需求:定义一个类,负责设置数据,和获取数据

    • 设置字符串数据
      class Demo{
          private String value;
          public String getValue() {
              return value;
          }
          public void setValue(String value) {
              this.value = value;
          }
      }
    • 设置Integer数据
      class Demo2{
          private Integer value;
          public Integer getValue() {
              return value;
          }
          public void setValue(Integer value) {
              this.value = value;
          }
      }

       上面书写的2个类的确可以设置值也可以获取值,但是它们只能给某个特定的类型来设置值和获取值。当类型不一致时,就无法设置和获取,为了能够给任意对象设置值和获取值,那么:

    • 可以把类中的变量类型定义Object类型。
      class Demo3{
          private Object value;
      
          public Object getValue() {
              return value;
          }
      
          public void setValue(Object value) {
              this.value = value;
          }
      }

      把类中的变量类型改成Object类型之后的确可以保存任意类型的数据,但是调用获取方法时返回的却变成了Object类型,当要使用对象的特有数据时,又要向下转型。这时我们可以使用泛型技术来完成需求。

      这时可以把泛型定义在类上,定以在类上的泛型,就相当于给这个类定义了参数,当使用这个类的时候,要求使用者来指明这个参数到底是什么类型。当把泛型定义在类上时,这个类就成为泛型类。定义在类上的泛型可以在类中直接使用

    • 泛型类
      class Demo4<IT>{
          private IT value;
      
          public IT getValue() {
              return value;
          }
      
          public void setValue(IT value) {
              this.value = value;
          }
      }
      public class GenericDemo {
          public static void main(String[] args) {
              //创建拥有泛型的类对象时,要求指明具体的泛型类型
              Demo4<String> d4 = new Demo4<String>();
              d4.setValue("aaaa");
              String value = d4.getValue();
              
              Demo4<Integer> d5 = new Demo4<Integer>();
              d5.setValue(123);
              Integer value2 = d5.getValue();
          }
      }

    泛型方法及静态方法泛型

      定义在类上的泛型可以在类中的成员变量方法上使用。有时我们也会遇到方法上要使用的泛型和类上定义的不一致,这时就需要把泛型定义在方法上

    • //类上定义的泛型
      class Test<W>{
          private W value;
          //方法上使用类上的泛型
          public void show( W w){
              System.out.println(w);
          }
          /*
           * 定义功能,专门负责打印任何数据,可以在这个方法上定义泛型
           * 在方法上定义的泛型,必须写在返回值的前面
           */
          public <Q> void print( Q q ){
              System.out.println(q);
          }
          /*
           * 静态方法无法使用类上的泛型。
           * 因为类上的泛型的具体类型必须是在创建本类对象的时候明确。
           * 而静态的方法它不需要对象就可以直接执行。
           */
          public static <T> void method( T w ){
              System.out.println(w);
          }
      }
      public class GenericDemo4{
          public static void main(String[] args) {
              Test<String> t = new Test<>();
              t.print("aaa");
              t.print(123);
              t.print(new  Object());
      Test.method("bbb"); } }

    泛型接口和泛型传递

    • 泛型接口,即:把泛型定义在接口上,泛型接口。
    • 把泛型定义在类上,创建这个类对象的时候,由具体的创建者来明确具体的泛型类型
    • 定义在接口上,接口是要有实现类来实现这个接口。这时就可以在实现这个接口的时候明确具体的泛型
    • 当在定义一个类实现某个接口的时候,如果接口上有泛型,但是当前这个实现并不能明确具体的类型时,这时这个实现类可以继续把泛型往下传递,最后后具体创建这个实现类对象的使用这个类明确具体的泛型。这个技术称为泛型的传递
    • 定义泛型接口
      interface Inter<W>{
          public void show(W w);
      }
    • 实现类实现泛型接口
      /*
       * 在书写接口的实现类,就是在使用接口,这时可以明确接口上的泛型类型
       */
      class InterImpl implements Inter<String>{
          @Override
          public void show(String w) {
              System.out.println(w);
          }
      }
    • 泛型的传递
      //interface Collection<E>{}
      //interface List<E> extends Collection<E>{}
      //class ArrayList<E> implements List<E>{}
      /*
       * 在定义实现类的时候,如果不知道接口中泛型的具体类型时,可以继续使用泛型
       */
      class InterImpl2<W> implements Inter<W>{
          public void show(W w) {
          }
      }
      public class GenericDemo5{
          public static void main(String[] args) {
              InterImpl2<String> in = new InterImpl2<>();
          }
      }

    泛型通配符

      使用一个符号来匹配所有的数据。这个符号就被称为通配符。

    • 需求:

      定义功能,专门用来打印集合中的数据

       * 打印集合,就是使用遍历,取出集合中的每个元素,然后打印在屏幕上即可。

      public class GenericDemo7 {
          public static void main(String[] args) {
              ArrayList<String> al = new ArrayList<String>();
              
              Collections.addAll(al, "aaaa","dddd","rrrrr","sssss","itcast","ABCD");
              
              printCollection(al);
              
              LinkedList<Integer> ll = new LinkedList<Integer>();
              ll.add(123);
              ll.add(333);
              ll.add(444);
              ll.add(5555);
              
              printCollection(ll);
          }
          /*
           * 定义功能负责打印Collection集合中的元素
           * 这个方法要打印的Collection集合中的元素,这时并不知道真正传递进来的容器中存放的是什么类型的元素。
           * 在定义功能的时候,无法明确Collection的泛型类型。
           * 这时可以使用泛型中的通配符来代替。
           * Java中泛型的通配符可以使用?来表示
           *  Collection<?> coll 当前这个方法可以接收Collection下的所有子集合。?表示的是子集合中的元素类型,
           *  当传递的子集合中存放的是什么类型,?就代表什么类型
           */
          public static  void printCollection( Collection<?> coll ){
              for (Iterator<?> it = coll.iterator(); it.hasNext();) {
                  System.out.println(it.next());
              }
          }
          /*
          public static void printCollection( ArrayList<String> coll ){
              for (Iterator<String> it = coll.iterator(); it.hasNext();) {
                  System.out.println(it.next());
              }
          }
          public static void printCollection( LinkedList<Integer> coll ){
              for (Iterator<Integer> it = coll.iterator(); it.hasNext();) {
                  System.out.println(it.next());
              }
          }
          */
      }

    泛型上下限

    • /*
       * 泛型的限定
       */
      public class GenericDemo6 {
          public static void main(String[] args) {
              //这个容器中存放Student对象
              ArrayList<Student> al = new ArrayList<Student>();
              
              al.add(new  Student("zhangsan",23));
              al.add(new  Student("lsi",23));
              al.add(new  Student("wangwu",23));
              al.add(new  Student("zhaoliu",23));
              al.add(new  Student("zhangsan",23));
              
              printCollection(al);
              
              //这个容器中存放Person对象
              ArrayList<Person> al2 = new ArrayList<Person>();
              
              al2.add(new  Person("zhangsan",23));
              al2.add(new  Person("lsi",23));
              al2.add(new  Person("wangwu",23));
              al2.add(new  Person("zhaoliu",23));
              al2.add(new  Person("zhangsan",23));
              
              printCollection(al2);
              //这个容器中存放Worker对象
              LinkedList<Worker> ll = new LinkedList<Worker>();
              
              ll.add(new  Worker("xiaoqiang",33));
              ll.add(new  Worker("wangcai",32));
              ll.add(new  Worker("huaan",28));
              ll.add(new  Worker("qiuxiang",18));
              
              //printCollection(ll);
          }
          /*
           * 这个方法Collection<?> coll 它可以接收Collection下的所有子类,并且可以打印其中的数据
           * 现在对这个方法进行限定,可以打印集合中的元素,但是要求集合中的元素必须是Person类型或者是Person的子类类型
           * 这时需要在方法上加泛型的限定
           *     泛型的上限限定    ? extends Person  这里表示?可以是Person本身,也可以是Person的子类类型
           *     泛型的下限限定   ? super Student  这里?表示当前可以是 Student类型,也可以是Student的父类类型
           */
          public static  void printCollection( Collection< ? extends Person > coll ){
              for (Iterator<?> it = coll.iterator(); it.hasNext();) {
                  System.out.println(it.next());
              }
          }
      }

    泛型在API中的应用

    以TreeSet构造方法为例:

    public  class   TreeSet<E> implements Set<E>{
        public TreeSet(){}
    }

    //可以接收一个集合作为创建TreeSet容器时的初始化数据

    public TreeSet( Collection<  ?  extends E >  c ){}

    这个构造方法主要作用用于创建TreeSet集合,在创建这个集合的时候可以给其传递一个Collection下的子集合,作为TreeSet集合的创建时的初始数据。

    TreeSet<...> set  =  new  TreeSet<...>(...)

    在创建TreeSet集合对象的时候,明确了泛型,那么就表示TreeSet定义的E泛型就被明确出来了。由于TreeSet集合要对其中的元素进行排序。

    在明确的这个E一定是具备排序的功能。那么在创建TreeSet的时候,传递另外一个集合进来,就要求传递进来的这个集合中的元素一定要能够和E进行比较,然后进行排序。

    Collection<  ?  extends E >  这里限定上限的原因是由于创建TreeSet集合的时候明确的类型E类型,那么给TreeSet集合对象初始数据的时候,初始的数据可以E本身,也可以是E的子类类型, 这个样就能够保证在TreeSet集合中存放下。

    public TreeSet(Comparator<? super E> comparator) {

     创建TreeSet集合的时候,可以传递比较器。比较器的功能是对集合中的元素进行比较的。

    比较器就要从集合中把元素取出来,对其中的元素进行比较。比较器首先要从集合中把元素取出来,并且比较器就要使用响应的类型来接收取出的这些元素。

    new TreeSet<E> (new  Copmarator(){});

    Collecions工具类中的方法

                          定义泛型                                       返回值类型     方法名         参数列表

    public static   <T extends Object & Comparable<? super T>>    T       max    (Collection<? extends T> coll)    {

     <T extends Object & Comparable<? super T>> T这个类型必须是Object子类同时T类型还要实现Comparable接口

    }

    Java总结篇系列:Java泛型

  • 相关阅读:
    【canvas】--------------处理canvas物理像素模糊问题-------------【劉】
    【js】--------------判断一个对象是否有某个属性-------------【劉】
    【vue】--------------vue+element-ui实现分页效果-------------【劉】
    【html】--------------iframe-------------【劉】
    【劉】---------------单页面和多页面的区别
    【react】--------------flux-------------【劉】
    【vue】--------------vue路由懒加载-------------【劉】
    【git】--------------git基本指令-------------【劉】
    【git】--------------git基本介绍-------------【劉】
    datatable 分组
  • 原文地址:https://www.cnblogs.com/cb0327/p/7119203.html
Copyright © 2011-2022 走看看