Java 泛型

来源:互联网 发布:李小璐遇网络诈骗 编辑:程序博客网 时间:2024/06/06 03:59

Java泛型简介

        泛型是Java SE 1.5新特性,泛型的本质是参数化类型,即操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称之为泛型类、泛型接口、泛型方法。Java语言引入泛型的好处是安全简单。

        在Java SE 1.5之前,没有泛型的情况下,通过对Object的引用来实现参数的“任意化”,但这样带来的缺点是要做显示的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译时期无法发现,在运行期才会出异常,这是一个安全隐患。

        简而言之,泛型的好处就是在编译期检查类型安全,并且所有的强制转换都是隐式的,提高了代码的重用率。

Java泛型实例

泛型类实例:

public class GenericsDemo {public static void main(String args[]) {// 泛型类使用Utils<Person> u = new Utils<Person>();u.setObject(new Person("zhangsan", 20));Person p = u.getObject();System.out.println("name:" + p.name + "; age: " + p.age);// 泛型方法使用Utils.print("zhangsan");Utils.print(20);}}// 泛型类定义class Utils<T> {private T t;public void setObject(T t) {this.t = t;}public T getObject() {return t;}// 泛型方法定义public static <E> void print(E e) {System.out.println("print: " + e);}}class Person {public String name;public Integer age;Person(String name, Integer age) {this.name = name;this.age = age;}}
        泛型类:在类名后面加上<T>指定类型,T即可在该类中作为一个固定类型来用。在没有泛型前是在公共类中定义Object对象(因为Object是所有类的父类),再通过父类引用指向子类对象来对子类对象进行处理,然后返回这个父类引用,再将这个父类引用的对象强转成我们需要的子类对象。这个过程就涉及到强制转换的问题,当然如果程序员能够很精准的使用对象是没有问题的;但如果程序员在对象的转换时有错误,则在编译期无法提示错误,只有到实际运行时才会出现异常。而使用泛型类则在定义使用时就需要指定类型,如果后面使用的类型存在问题则在编译期就能提示错误,这显然优于类型的强转(软件问题发现的越早,损失相对也就越小)。还有就是泛型的强转是隐式的,不须要显示调用,简化了代码。

        泛型方法:上例中还定义了一个泛型方法,泛型方法时在“返回值”前用<E>指定类型,E在该方法中也可作为一个固定类型来使用。另外注意一点,静态方法不能使用泛型类指定的类型T,泛型类的T是在实例化对象时才指定的。T和E只是一个标识符,用其它名称均可,只是大家习惯使用T和E。

泛型接口实例:

public class GenericsDemo {public static void main(String args[]) {// 泛型类和接口的应用InterImpl<String> i = new InterImpl<String>();i.show("hello world!");Inter<Integer> ii = new InterImpl<Integer>();ii.show(365);}}// 泛型接口interface Inter<T> {void show(T t);}// 泛型类实现泛型接口,当然这里也可以用指定类型来实现泛型接口class InterImpl<T> implements Inter<T> {public void show(T t) {System.out.println("show: " + t);}}
        接口本身是定义规则,通过类来实现功能的。只有在接口上也定义了泛型,子类在实现时才能对其进行重写,从而获取泛型类的优势。

Java泛型高级应用

        这里使用到了一个?的特殊符号,先解释下?:表示通配符,对不确定类型的一种替代。通配符时什么东西,我们不是很懂,但对不确定类型的一种替代这个应该见过吧。在上面讲到的泛型类中,我们对不确定类型不就是通过T来替代的么。简而观之:?和T在功能上有重叠,那为什么有了T还再弄个?出来呢。先看一段实例。

import java.util.ArrayList;import java.util.Iterator;import java.util.List;public class GenericsDemo {public static void main(String args[]) {// 测试数据List<Person> pl = new ArrayList<Person>();pl.add(new Person("person01", 10));pl.add(new Person("person02", 20));pl.add(new Person("person03", 30));List<Student> sl = new ArrayList<Student>();sl.add(new Student("student01", 10, 10.1F));sl.add(new Student("student02", 20, 20.1F));sl.add(new Student("student03", 30, 30.1F));List<Worker> wl = new ArrayList<Worker>();wl.add(new Worker("worker01", 10, 10.1F));wl.add(new Worker("worker02", 20, 20.1F));wl.add(new Worker("worker03", 30, 30.1F));// TPerson pt = showT(pl);System.out.println("name: " + pt.name + "; age: " + pt.age);Student st = showT(sl);System.out.println("name: " + st.name + "; age: " + st.age + "; grade: " + st.grade);Worker wt = showT(wl);System.out.println("name: " + wt.name + "; age: " + wt.age + "; grade: " + wt.salary);showT(new ArrayList<Object>());// ?show(pl);show(sl);show(wl);show(new ArrayList<Object>());// 泛型上限showUp(pl);showUp(sl);showUp(wl);//showUp(new ArrayList<Object>());// 此处无法编译通过,因为超出了泛型的上限,非Person或子类无法接收// 泛型下限showDown(sl);showDown(pl);//showDown(wl); // 此处编译失败,因为超出了泛型的下限,非Student或父类无法接收showDown(new ArrayList<Object>());}// Tpublic static <T> T showT(List<T> pList) {Iterator<T> it = pList.iterator();while(it.hasNext()) {T t = it.next();// 此时t也只能使用Object对象的方法System.out.println("name: " + t.toString());return t;}return null;}// ?public static void show(List<?> pList) {Iterator<?> it = pList.iterator();while(it.hasNext()) {// 返回的是Object对象Object obj = it.next();System.out.println("show ?: " + obj);}}// 泛型上限public static void showUp(List<? extends Person> pList){Iterator<? extends Person> it = pList.iterator();while(it.hasNext()) {// 使用泛型上限时,List中的最顶层类指能是Person,所以返回父类引用对象Person p = it.next();// 此时p能使用Person对象的方法System.out.println("name: " + p.name + "; age: " + p.age);}}// 泛型下限public static void showDown(List<? super Student> pList){Iterator<? super Student> it = pList.iterator();while(it.hasNext()) {// 使用泛型下限时,对List中的类型不确定,所以返回所有类的基类Object对象Object obj = it.next();// 此时p只能使用Object对象的方法System.out.println("showDown: " + obj);}}}// 测试支持类class Person {public String name;public Integer age;Person(String name, Integer age) {this.name = name;this.age = age;}}class Student extends Person{public Float grade;Student(String name, Integer age, Float grade) {super(name, age);this.grade = grade;}}class Worker extends Person{public Float salary;Worker(String name, Integer age, Float salary) {super(name, age);this.salary = salary;}}
        T与?简单对比:

        很明显对于使用T和?,在接收参数上两者功能基本类似,都能接收任意类型的集合对象;对对象的操作,两者都是将对象默认成Object类型,只能调用Object对象的方法;在返回值上,T可以返回一个T类型的对象,而?只能返回一个Object对象。在这个地方应该对T是一种类型,?是一种通配符有点理解了吧;T作为类型,也就能定义返回值的类型,而?是通配符,只是暂时用来替代某一对象,也就不能定义返回值的类型了。

        泛型上限:

        当<? extends Person>时,表示此时接收的参数是有上限的,该实例中就只能接受Person类以及Person的子类;对对象的操作,是将对象转换为Person对象,能调用Person中的方法对对象进行处理;返回值是Person对象引用。
        泛型下限:

        当<? super Student>时,表示此时接收的参数是有下限的,该实例中就只能接受Student类以及Student的父类;对对象的操作,是将对象转换为Object对象,只能调用Object对象中的方法;返回值是Object对象的引用。

        这里对泛型的创建和使用有了个基本的介绍。关于泛型的使用,首先是要理解使用泛型的好处和局限性(好处:避免了对Object的强转,提高了安全性;局限性:在内部操作时不能使用对象特有的方法),就知道在什么时候去合理的设计使用泛型。




0 0