前言

  • 泛型实现了参数化类型的概念;
  • 泛型的主要目的之一是用来指定容器要持有什么类型的对象,编译器保证类型的正确性;
  • 多态也是一种泛化机制;
  • 基本类型无法作为类型参数;

一.基本使用方式

  泛型基本分为泛型类型和泛型方法两种,泛型类型声明方式为类型参数用尖括号括住,放在类名后边,泛型方法的参数列表应该置于返回值之前。示例如下:

//泛型类
package java.lang;

public interface Iterable<T> {
    Iterator<T> iterator();

    default void forEach(Consumer<? super T> action) {
        Objects.requireNonNull(action);
        for (T t : this) {
            action.accept(t);
        }
    }

    default Spliterator<T> spliterator() {
         return Spliterators.spliteratorUnknownSize(iterator(), 0);
    }
}

//泛型方法
public class GenericMethods{
    public <T> void f(T t){
        System.out.println(t.getClass().getName());
    }
}
  • 应该优先使用泛型方法,而非将泛型应用到整个类上;
  • 泛型的核心概念是告诉编译器想使用什么类型,然后让编译器处理细节.

二.使用场景

1.元组类库

  即当调用一个方法希望返回多个对象时,需要将一组对象直接打包存储在一个对象中——这也是元祖的概念。元组中的对象可以是不同的类型。示例代码如下:

//二维元祖
public class TwoTuple<A,B>{
    public final A first;//fixme 注意是final类型的
    public final B second;

    public TwoTuple(A first, B second) {
        this.first = first;
        this.second = second;
    }
}

//使用继承机制实现的三维元祖
class ThreeTuple<A,B,C> extends TwoTuple<A,B>{
    public final C third;

    public ThreeTuple(A first, B second, C third) {
        super(first, second);
        this.third = third;
    }
}
  • 使用继承机制实现更长的元组;
  • 变量为final类型保证了元组对象被创建后,final元素便不能被改变了;
2.实现堆栈类

  可以使用泛型类实现自定义的链表栈,示例如下:

package fanxing;

 public class LinkedStack<T> {
    private static class Node<U>{
        U item;
        Node<U> next;
        Node(){item=null;next=null;}

        public Node(U item, Node<U> next) {
            this.item = item;
            this.next = next;
        }
        //末端哨兵(end sentinel)
        boolean end(){
            return item==null&&next==null;
        }
    }
    private Node<T> top=new Node<>();
    //每push一次都会创建一个对象并放到栈尾
    public void push(T item){
        top=new Node<>(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<>();
        for(String str:"du gen kui".split(" "))
            lss.push(str);
        String s;
        while((s=lss.pop())!=null)
            System.out.println(s);
    }
}
3.用于工厂方法设计模式

  泛型可以用于接口,比如生成器(generator),工厂方法设计模式是其一中应用。例如crawl4j中的工厂方法:

public interface WebCrawlerFactory<T extends WebCrawler> {
    T newInstance() throws Exception;
}

//补充:默认工厂的实现
class DefaultWebCrawlerFactory<T extends WebCrawler> implements WebCrawlerFactory<T>{
    final Class<T> claz;
    DefaultWebCrawlerFactory(Class<T> clz){ this.clz=clz;}
    
    @Override
    public T newInstance() throw Exception{
        try{
            return clz.newInstance();
        }catch(ReflectiveOperationException e){
            throw e;
        }
    }
}
4.补充:可变参数列表

  将方法参数项写成T... x的形式就可以将其作为可变参数列表。示例如下:

public class VariableParam<T> {

    public void testFunc(T... params){
        for (T ele:params) {
            System.out.println(ele.toString());
        }
    }

    public static void main(String[] args) {
        new VariableParam<String>().testFunc("du","gen","kui");
    }
}