泛型

来源:互联网 发布:知乎ipad客户端 编辑:程序博客网 时间:2024/06/06 05:33

一: 一个元组类库
1. 什么是元组
这里写图片描述

  1. 元组能做什么
    调用一次方法能够返回多个对象
  2. 元组特性:
    元组可以是任意长度,元组中的长度可以是任意类型
  3. 实现元组
    定义泛型类,通过继承机制实现长度更长的元组
    类的属性定义为final是出于安全考虑,外部类不能随意修改
  4. 实例
    package com;      class Automobile{};      class cx<A,B>{          public final A a;          public final B b;          protected cx(A a,B b)          {              this.a=a;              this.b=b;          }          public A getA() {              return a;          }          public B getB() {              return b;          }          public String toString()          {              return "("+a+","+b+")";          }      }      class cx_a<A,B,C> extends cx<A,B>      {          public final C c;          public C getC() {              return c;          }          public cx_a(A a, B b,C c) {              super(a, b);              this.c=c;              // TODO Auto-generated constructor stub          }          public String toString()          {              return "("+a+","+b+","+c+")";          }      }      class cx_b<A,B,C,D> extends cx_a<A,B,C>      {          public final D d;          public cx_b(A a,B b,C c,D d)          {              super(a,b,c);              this.d=d;          }          public D getD() {              return d;          }          public String toString()          {              return "("+a+","+b+","+c+","+d+")";          }      }      public class test<A,B,C,D,E> extends cx_b<A,B,C,D>      {          private final E e;          public test(A a,B b,C c,D d,E e)          {              super(a,b,c,d);              this.e=e;          }          public E getE() {              return e;          }          public String toString()          {              return "("+a+","+b+","+c+","+d+","+e+")";          }          public static void main(String[] args) {              test<String,Integer,String,String,Long> temp=new test<String,Integer,String,String,Long>("a",3,"b","c",(long) 345);              System.out.println(temp.toString());          }      }  

二:一个堆栈类

用LinkedList可以实现栈,这里我们不用LinkedList,采用内部链式存储机制来实现、

这里写图片描述

Node(3,top)其中的top是Node(2,top)
Node(2,top)其中的top是Node(1,top)

public class LinkedStack<T> {      private static class Node<U> {        U item;        Node<U> next;        Node() { item = null; next = null; }        Node(U item, Node<U> next) {          this.item = item;          this.next = next;        }        boolean end() { return item == null && next == null; }      }      private Node<T> top = new Node<T>(); // End sentinel      public void push(T item) {        top = new Node<T>(item, top);      }          public T pop() {        T result = top.item;        if(!top.end())          top = top.next;        return result;      }      public static void main(String[] args) {//      LinkedStack<String> lss = new LinkedStack<String>();//      for(String s : "Phasers on stun!".split(" "))//        lss.push(s);//      String ss;//      while((ss = lss.pop()) != null)//        System.out.println(ss);          //----- if put integer into the LinkedList          LinkedStack<Integer> lii = new LinkedStack<Integer>();          for(Integer i = 0; i < 10; i++){              lii.push(i);          }          Integer end;          while((end = lii.pop()) != null)              System.out.println(end);          //----- integer test end!      }    }

三:RandomList
这里写图片描述

class RandomList<T> {      private ArrayList<T> storage = new ArrayList<T>();      private Random rand = new Random(47);      public void add(T item) { storage.add(item); }      public T select() {        return storage.get(rand.nextInt(storage.size()));      }      public static void main(String[] args) {        RandomList<String> rs = new RandomList<String>();        for(String s: ("The quick brown fox jumped over " +            "the lazy brown dog").split(" "))          rs.add(s);        for(int i = 0; i < 11; i++)          System.out.print(rs.select() + " ");      }    } 

四:泛型接口

package generics;import java.util.Iterator;import java.util.Random;interface Generator<T> {    T next();}// 方法next()的返回类型是参数化的T。正如你所见到的,接口使用泛型与类使用泛型没什么区别。// 为了演示如何实现Generator接口,我们还需要一些别的类。例如,Coffee类层次结构如下:// Java代码 收藏代码class Coffee {    private static long counter;// 编号,初始值为0    private final long id = counter++;    public String toString() {        return getClass().getSimpleName() + " " + id;    }}class Mocha extends Coffee {}class Latte extends Coffee {}class Breve extends Coffee {}// 现在,我们可以编写一个类,实现Generator<Coffee>接口,它能够随机生成不同类型的Coffee对象:// Java代码 收藏代码public class CoffeeGenerator implements Generator<Coffee>, Iterable<Coffee> {    private Class[] types = { Latte.class, Mocha.class, Breve.class, };    private static Random rand = new Random(47);    public CoffeeGenerator() {    }    // 为了使用For循环对该类实例进行迭代时次数控制:    private int size = 0;    public CoffeeGenerator(int sz) {        size = sz;    }    public Coffee next() {        try {            // 随机返回一个Coffee实例            return (Coffee) types[rand.nextInt(types.length)].newInstance();        } catch (Exception e) {            throw new RuntimeException(e);        }    }    // 实现Iterator接口,这里属于黑箱迭代子模式    private class CoffeeIterator implements Iterator<Coffee> {        int count = size;        public boolean hasNext() {            return count > 0;        }        public Coffee next() {            count--;            // 调用外部类的next方法,所以前面要明确指定外部类类型,            // 不然的话就是调用内部类自身的方法了            return CoffeeGenerator.this.next();        }        public void remove() { // Not implemented            throw new UnsupportedOperationException();        }    };    // 向外界提供迭代器的实现,这样可以用在foreach循环语句中    public Iterator<Coffee> iterator() {        return new CoffeeIterator();    }    public static void main(String[] args) {        CoffeeGenerator gen = new CoffeeGenerator();//       不使用迭代接口Iterator进行迭代时,由程序外部自己控制迭代过程        for (int i = 0; i < 5; i++) {            /*             * 某次输出: Breve 0 Breve 1 Mocha 2 Breve 3 Mocha 4             */            System.out.println(gen.next());        }        /*         * 使用增加for循环,CoffeeGenerator实现了Iterable接口,所以它可以在         * 循环语句中使用。使用迭代子模式时迭代过程由迭代器来控制         */        for (Coffee c : new CoffeeGenerator(5)) {            /*             * 某次输出: Breve 5 Mocha 6 Breve 7 Latte 8 Mocha 9             */            System.out.println(c);        }    }}

使用Generator<T>接口生成斐波那契数列

public class Fibonacci implements Generator<Integer> {      protected int count = 0;//计数器      public Integer next() {          return fib(count++);//自动装箱      }      //递归求某数的斐波拉契      private int fib(int n) {          if (n < 2) {              return 1;          }          return fib(n - 2) + fib(n - 1);      }      public static void main(String[] args) {          Fibonacci gen = new Fibonacci();          //输出0-9的斐波拉契          for (int i = 0; i < 10; i++) {              /*              * Output: 1(0) 1(1) 2(2) 3(3) 5(4) 8(5) 13(6) 21(7) 34(8) 55(9)              */              System.out.print(gen.next());          }      }      public int getIndex() {          return count - 1;      }  }  

五:泛型方法
这里写图片描述
1.泛型方法比泛型类的优势之处:
(1)泛型方法使得方法能够独立于类而产生变化
(2)调用方法时调用static方法更方便,但是static方法无法访问泛型类的类型参数,所以如果static方法需要使用泛型能力,就必须成为泛型方法。
(3)使用泛型方法时通常不用指明参数类型(因为编译器会为我们找出具体的类型,这称为类型参数判断),而使用泛型类时必须在创建对象时指定类型参数的值
例:

//泛型方法public class GenericMethods {    public <T> void f(T x){        System.out.println(x.getClass().getName());    }    public static void main(String[] args) {        GenericMethods gm = new GenericMethods();        gm.f("");        gm.f(1);        gm.f(1.0);        gm.f(1.0f);        gm.f(1.0f);        gm.f('c');        gm.f(gm);    }}

2.杠杆利用类型参数推断

首先是一个静态方法:

class New1 {  public static <K, V> Map<K, V> map(){    return new HashMap<K, V>();  }  // 然后可以这样创建一个Map:  public static void test(String[] args){    Map<String, List<Cat>> catMap = New.map();  }}

可以发现,右边的不用再按照以前的这种写法了:

Map<String, List> catMap = new HashMap<String, List>();

左边声明部分的类型为右边提供了一种推断,使得编译器可以直接创造出来具体的类了。不过,这种场景没有声明,直接使用New.map()是编译不通过的,因为没有像这里左边的可以推断的依据了, 如下面的,加入f()是一个方法,需要传入一个Map,如下的写法是编译不通过的:
f(New.map());

如果确实还是想按照上面那样使用,则可以考虑使用显示类型说明了,在操作符与方法名直接插入尖括号显示的指明类型,代码如下:

F(New.<Person, List>map());

不过这种方式很少使用。也就是说,在编写非赋值语句时,才要这样的说明,而使用不了杠杆利用类型推断。

我们为了方便,可以使用同样的方式创建其他的容器了,可惜JDK本身没有提供这样的类:

class New {    public static <K,V> Map<K,V> map() {      return new HashMap<K,V>();    }    public static <T> List<T> list() {      return new ArrayList<T>();    }    public static <T> LinkedList<T> lList() {      return new LinkedList<T>();    }    public static <T> Set<T> set() {      return new HashSet<T>();    }     public static <T> Queue<T> queue() {      return new LinkedList<T>();    }    // Examples:    public static void test(String[] args) {      Map<String, List<String>> sls = New.map();      List<String> ls = New.list();      LinkedList<String> lls = New.lList();      Set<String> ss = New.set();      Queue<String> qs = New.queue();    }}

3.可变参数也是可以使用泛型声明类型的:

public class GenericVarargs {      public static <T> List<T> makeList(T... args){        List<T> result = new ArrayList<T>();        for(T item : args){          result.add(item);        }        return result;      }      public static void main(String[] args) {          List<String> ls = makeList("A");          System.out.println(ls);          ls = makeList("A","B","C");          System.out.println(ls);          ls = makeList("A","B","C","D","E");          System.out.println(ls);    }}
原创粉丝点击