泛型

一: 一个元组类库
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);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值