教你如何使用Java泛型

泛型( Generic)实现了参数化类型的概念,使得代码可以应用于多种类型。我们常用的ArrayList<T>HashMap<K,V>等都是使用了泛型。泛型的意思就是可以适用于许多种的类型
Java的核心概念就是:告诉编译器想使用什么类型,然后编译器帮你处理一切细节

泛型类

我们最常见的就是泛型类了,比如我们上面提到的ArrayList<T>HashMap<K,V>等等。下面我们以一个具体的例子,看看如何创建一个自己的泛型类。
创建一个堆栈类,实现简单的入栈和出栈操作。

package genericdemo.classdemo;


/**
 * 利用泛型实现一个简单的堆栈类
 * @author nxiangbo
 *
 * @param <T>
 */
public class LinkedStack<T> {
    /**
     * 内部类Node是一个泛型。
     * @author nxiangbo
     * 
     * @param <E>
     */
    private static class Node<E>{
        E item;
        Node<E> next;
        public Node() {
            item = null;
            next = null;
        }
        public Node(E item, Node<E> next){
            this.item = item;
            this.next = next;
        }

        private boolean end() {
            return (item==null)&&(next==null);
        }
    }

    private Node<T> top = new Node<T>();

    /**
     * 入栈
     * @param item
     */
    public void push(T item){
        top = new Node<T>(item, top); 
    }

    /**
     * 出栈
     * @return
     */
    public T pop(){
        T result = top.item;
        if(!top.end()){
            top = top.next;
        }
        return result;
    }

}

下面测试一下上述泛型类如何使用的。

public static void main(String[] args) {
        //String 类型的
        LinkedStack<String> lsStr = new LinkedStack<String>();
        String strs = "this is generic demo";
        for (String string : strs.split(" ")) {
            lsStr.push(string);
        }

        System.out.println(lsStr.pop());

        //int类型的
        LinkedStack<Integer> lsInt  = new LinkedStack<>();
        int[] nums = {12,43,54,23,43,12345};
        for (int i : nums) {
            lsInt.push(i);
        }

        System.out.println(lsInt.pop());
泛型接口

泛型接口
泛型也可以应用于接口。例如生成器(Generator),这是一种专门负责创建对象的类。实际上这是工厂方法设计模式中的一种应用。
一般而言,一个生成器只定义一个方法,该方法用于产生新的对象。
接口的定义

package genericdemo.interfacedemo;

/**
 * 泛型接口
 * @author nxiangbo
 *
 */
public interface Generator<T> {
    //返回的是参数类型`T`
    T next();
}

那么,该如何使用泛型接口呢??
我们以斐波那契数为例子,来说明一下,泛型接口如何使用。

public class Fibonacci implements Generator<Integer>{
    private int count = 0;
    private int fib(int n){
        if(n <2){
            return 1;
        }
        return fib(n-2)+fib(n-1);
    }

    @Override
    public Integer next() {

        return fib(count++);
    }

    public static void main(String[] args) {
        Fibonacci finGen = new Fibonacci();
        for (int i = 0; i < 8; i++) {
            System.out.print(finGen.next()+", ");
        }
    }
}

by the way,基本类型无法做为类型参数。比如上面的Generator<Integer>,不能写成Generator<int>, 以及ArrayList<Integer>,不能写成ArrayList<int>等等。

泛型方法

到目前为止,我们都是将泛型应用在类中,但也可以在类中包含参数化方法,而这个方法可以是泛型类,也可以不是泛型类。

泛型方法使得该方法能够独立于类而产生变化。一个基本原则是:无论何时,只要能够使用泛型,就应该尽量使用泛型。如果使用泛型方法可以取代泛型类,那么就应该只使用泛型方法。另外,对于一个static方法,无法访问泛型类的类型参数,所以,如果static方法需要使用泛型能力,就必须使用泛型方法。
泛型方法的定义:只需将泛型参数列表置于返回值之前。
泛型方法与泛型类不同的是: 泛型类在被使用时,必须指明参数类型。而泛型方法在被使用时,不必指明参数类型,因为编译器会为我们找出具体的类型,这称为类型参数推断(type argument inference)。
对于泛型类,由于编译器不能够从泛型参数列表中的一个参数推断出另一个参数。所以,我们每次使用Map等泛型时,必须这样,Map<String,String> map = new HashMap<String,String>。增加了很多的代码。因此,我们可以使用泛型方法构建一个工具类,用以简化泛型类的使用。
代码如下。

package genericdemo.methoddemo;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;

/**
 * 泛型方法
 * 可作为一个工具类,去简化HashMap<K,V>泛型的使用
 * @author nxiangbo
 *
 */
public class New {
    public static <K,V> Map<K, V> map(){
        return new HashMap<K, V>();
    }

    public static <T> java.util.List<T> list(){
        return new ArrayList<T>();
    }

    public static <T> LinkedList<T> linkedList(){
        return new LinkedList<>();
    }

    public static <T> Queue<T> queue(){
        return new LinkedList<>();
    }

    public static <T> Set<T> set(){
        return new HashSet<T>();
    }
}

有了这个工具类后,我们就可以很简单的声明泛型了。
具体使用如下。

public static void main(String[] args) {
        Map<String, String> map = New.map();
        java.util.List<String> list = New.list();
        LinkedList<String> linkedList = New.linkedList();
    }

下面我们再看一个关于泛型方法的例子。利用泛型方法,实现集合的并、交、补、差集的工具类。
代码如下。

package genericdemo.methoddemo;

import java.util.HashSet;
import java.util.Set;

/**
 * Sets工具类,实现集合的并、交、差、补集
 * @author nxiangbo
 *
 */
public class Sets {
    /**
     * 并集
     * @param set1
     * @param set2
     * @return
     */
    public static <T> Set<T> union(Set<T> set1, Set<T> set2){
        Set<T> result = new HashSet<T>(set1);
        result.addAll(set2);
        return result;
    }

    /**
     * 交集
     * @param set1
     * @param set2
     * @return
     */
    public static <T> Set<T> intersection(Set<T> set1, Set<T> set2){
        Set<T> result = new HashSet<T>(set1);
        result.retainAll(set2);
        return result;
    }

    /**
     * 差集
     * @param set1
     * @param set2
     * @return
     */
    public static <T> Set<T> difference(Set<T> set1, Set<T> set2){
        Set<T> result = new HashSet<T>(set1);
        result.removeAll(set2);
        return result;
    }

    /**
     * 补集
     * @param set1
     * @param set2
     * @return
     */
    public static <T> Set<T> complement(Set<T> set1, Set<T> set2){
        return difference(union(set1, set2), intersection(set1, set2));
    }


}

测试如下。

public static void main(String[] args) {
        Set<String> set1 = new HashSet<String>();
        set1.add("hash");
        set1.add("map");
        set1.add("list");

        Set<String> set2 = new HashSet<String>();
        set2.add("hash");
        set2.add("array");
        set2.add("list");

        System.out.println(union(set1, set2));
        System.out.println(intersection(set1, set2));
        System.out.println(difference(set1, set2));
    }
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值