教你如何使用Java泛型

来源:互联网 发布:树洞软件 编辑:程序博客网 时间:2024/06/18 15:54

泛型( 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));    }
1 0
原创粉丝点击