我相信很多人跟我一样还未学习过范型的概念就开始使用范型的实例,最典型的就是集合框架。为了进一步深入了解范型,这一次通过几个简单的例子来说明范型的注意事项。
一.没有范型的世界
所有的java类都派生自java.lang.Object ,这意味着所有的java对象都可以转换成Object,听起来似乎很美妙,但事实并非如此。举个例子,假设现在需要一伙人去排队,要求只有学生可以参与进来,但是如果对于这个队伍没有条件限定的话,那就意味着我们不想要的一些群体也会进入大军之中,这不利于管理。再如下面一段没有使用范型的代码:
List string=new ArrayList();
string.add("我是第一个元素");
string.add("我是第二个元素");
当要从中获取一个成员时,得到的却是java.lang.Object的一个实例,那么如果我们要使用String类型的对象还要进行强转型,这无疑增加了代码的冗杂度。不过幸好,我们有了范型。
二. 范型类型简介
像方法一样,范型类型也可以接受参数,声明范型类型要使用尖括号将类型变量列表括起来。例如声明一个List对象:
List<E> mylist;
为了将范型类型实例化,要在声明它的时候传递相同的参数列表,例如,为了创建一个使用String的ArrayList,要将String放在一对尖括号中进行传递:
List<String> string=new ArrayList<String>();
不过,java7版本之后,可以在参数化类的构造器中显式的传入参数,上面一段代码可以改为如下的表达方式:
List<String> string=new ArrayList< >();
毫无疑问范型类型也可以指定Object类型,但是范型类型却不可以是java.lang.Throwable的直接或间接子类,因为它在运行时抛出异常,因此无法查看在编译时会抛出什么异常。
下面一段代码就对使用了范型与未使用范型的List进行了比较:
import java.util.ArrayList; import java.util.List; public class GenericListTest { public static void main(String args[]){ //没有使用范型的队列 List stringList=new ArrayList(); stringList.add("元素1"); stringList.add("元素2"); //需要强转型 String s1=(String)stringList.get(0); System.out.println(s1); //使用范型的队列 List<String> list=new ArrayList<String>(); list.add("元素3"); list.add("元素4"); //不需要强转型 String s2=list.get(0); System.out.println(s2); } }
提示:使用范型类型时,是在编译时进行类型检查的。
这里值得关注的地方在于,范型类型本身也是一个类型,它还可以用作类型变量。
如下的一段代码演示:
import java.util.ArrayList; import java.util.List; public class ListOfList { public static void main(String args[]){ List<String> list=new ArrayList<>(); list.add("我是list中的对象"); //list中的元素 System.out.println(list.get(0)); //创建封装了list的List对象 List<List<String>> listOflist=new ArrayList<>(); listOflist.add(list); //获取list当中的元素 String s=listOflist.get(0).get(0); System.out.println(s); } }
范型类型可以接受不止一个类型变量,那就是我们非常熟悉的Map集合,相信大家也已经相当熟悉了吧
三. 使用“?”通配符
前面所提到的,如果声明一个List<aType>,那么List将使用aType的实例,并且可以保存以下任意一种类型:
1. aType的一个实例
2. aType的子类的一个实例,如果aType是类的话
3. 实现aType的类的一个实例,如果aType是接口的话
但是,注意范型类型本身也是一个java类型,如果你不理解的话,下面这段代码将会让你更加了解这句话的含义:
import java.util.ArrayList; import java.util.List; public class AllowedTypeTest { public static void main(String args[]){ List<String> myList=new ArrayList<String>(); doIt(myList); } private static void doIt(List<Object> l){ } }
编译产生了错误,按理说,String是Object的一个子类,但是进行了范型类型封装之后List<String>就不再是List<Object>的一个实例了。
为了解决这个问题,我们就要用到通配符“?”,如下:
import java.util.ArrayList; import java.util.List; public class WildCardTest { private static void doIt(List<?> l){ for(Object element:l){ System.out.print(element); } } public static void main(String args[]){ //字符型List List<String> stringList=new ArrayList<String>(); stringList.add("Hello"); stringList.add("World"); doIt(stringList); System.out.println(); //整型List List<Integer> intList=new ArrayList<Integer>(); intList.add(100); intList.add(200); doIt(intList); } }
代码中doIt方法里面的List<?>表示的是任意类型的一个List,但要注意的是,在声明或者创建一个范型类型时使用通配符是不合法的,如:
List<?> list=new ArrayList<?>();
编译会出错。
四. 在方法中使用有界通配符
通过上面的描述,你已经知道了可以使用“?”通配符来解决类型匹配的问题,但是我们在实际中碰到的问题并非这么简单。如果我们想定义一个Number实现子类的List,虽然我们可以用通配符来解决List<Integer>与List<Double>类型不匹配的问题,但是无疑的,我们还可以放入很多我们并不需要的实例如List<String>,这样程序的类型安全性根本就没有保障了,那么我们就必须需要一种规则来保证我们所定义的List实例是属于Number的实现子类的,在这里我们就要用到有界通配符。
如下演示:
import java.util.ArrayList; import java.util.List; public class BoundedWildcardTest { public static void main(String args[]){ List<Integer> intList=new ArrayList<>(); intList.add(3); intList.add(30); System.out.println(getAverage(intList)); List<Double> doubleList=new ArrayList<>(); doubleList.add(3.0); doubleList.add(30.0); System.out.println(getAverage(doubleList)); } private static double getAverage(List<? extends Number> list){ double total=0.0; for(Number number:list){ total+=number.doubleValue(); } return total/list.size(); } }
五.编写范型类型
编写范型类型与其他类型并无太大差异,只是在类中的某处声明需要用到的类型变量列表。下面就是范型类的一个简单示例:
public class MyGeneric<E> { E a; public MyGeneric(E a){ this.a=a; } public E get(){ return a; } public void set(E b){ this.a=b; } }
范型为我们的编码过程做出了巨大的贡献,提供了更加严格的类型检查,并且在取得元素时无需再进行类型转换,真乃编码之一大利器也。
相关推荐
消息传递范型与C/S范型双范型的主数据管理机制,陈晓云,邢乔金,本文针对主数据管理(MDM)存在的问题提出了一种基于消息传递机制范型与C/S范型双范型的主数据管理机制,当各个分系统的数据有所变化�
C++多范型设计,ISBN:9787508318240,作者:(美)James O.Coplien著;鄢爱兰,周辉等译;鄢爱兰译
Java 范型Java 范型
范型程序设计与 STL.pdf,大小约 300K。
第7章综合考虑前几章的内容,介绍了结构复杂性不同的设计问题的分类,以及可作为基于领域分析和多范型设计技术基础的高级活动集合。第8章研究结构复杂的设计,并介绍如何组合各种范型。第9章补充说明了流行的设计...
java1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.docjava1.5范型编程指南.doc
《分布式系统原理与范型》是分布式系统中的经典教材,全书分为两部分:原理和范型。第一部分详细讨论了分布式系统的原理、概念和技术,其中包括通信、进程、命名、同步、一致性和复制、容错以及安全。第二部分给出了...
《分布式系统原理与范型》第一版.中文版,影印版。
分布式系统原理与范型第二版课后习题答案 分布式系统原理与范型第二版课后习题答案 分布式系统原理与范型第二版课后习题答案 分布式系统原理与范型第二版课后习题答案
C++ 设计新思维 范型编程与设计模式之应用 pdf
分布式系统原理与范型.pdf tanenbaum的早期操作系统著作
C++多范型设计.pdfC++多范型设计.pdfC++多范型设计.pdf
详细介绍分布式原理和基本范型, 是一部不可多得的分布式经典书籍。
是《分布式系统原理与范型(第二版)》的答案 上回写错了,易造成误解! 本文档是第二版书的答案哦! 绝对是新的哦! 英文的!
第2~9章讨论的是分布式系统的的原理、概念和技术,包括通信、进程、命名、同步化、一致性和复制、容错性以及安全性等,而分布式应用的开发方法(即范型)在第10~13章中进行了讨论。但是,与前一版不同的是,我们...
深入探讨范型编程思想及C++语言中范型设计的应用
分布式系统-原理与范型(第2版) 分布式系统-原理与范型(第2版) 分布式系统-原理与范型(第2版) 分布式系统-原理与范型(第2版)
分布式系统原理与范型 第二版 详细介绍了分布式系统基础知识
分布式系统原理与范型中文版 经典分布式理论书籍