教你如何使用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)); }
- 教你如何使用Java泛型
- 图解教你如何使用ANT打包java程序
- 图解教你如何使用ANT打包java程序
- 教你如何使用UIWebView
- 教你如何使用Dwr
- 教你如何使用FastJson
- 教你如何使用session
- 教你如何使用Gerrit
- 使用实例教你如何使用log4j
- 教你如何使用JSONP数据格式,如何使用jQuery
- 教你如何使用java语言编写一个简单的SqlHelper类
- Java零基础:一步步教你如何使用eclipse创建项目及编写小程序实例
- 教你如何使用Google进行搜索
- 教你如何使用Google进行搜索
- 教你如何使用maxscript调试器
- 教你如何使用真正的Google
- 教你如何使用 Google App Engine
- 专家教你如何使用google
- 20160319 CodeVs 1073 家族,2033 邮票,1026 逃跑的拉尔夫
- 深入理解Java虚拟机笔记---引用类型和对象是否死亡
- 使用JSP处理用户注册和登陆
- Android处理滑动与点击事件的冲突
- 看懂此文,不再困惑于javascript中的事件绑定、事件冒泡、事件捕获和事件执行顺序
- 教你如何使用Java泛型
- CAShapeLayer和CAGradientLayer
- PCH文件的配置
- hdu1176
- hdu 3182 Hamburger Magi(状压dp)
- 实现HI-LO猜游戏
- 【NOIP2013提高组day1】火柴排队
- linux下socket连接下的心跳机制
- 蘑菇街 App 的组件化之路