JDK5.0新特性之:泛型

文/陈刚 2005-11-09 

一、前言

  泛型这个词在现在的JAVA挺时髦,光从字面上你是无法知道它代表些什么东东的,所以我们还是不要从字面去理解,而是从一些实例去了解它吧。

二、泛型之前的日子

  JDK1.4之前是没有泛型的概念的,所以我们才会有下面的代码:

        List list = new ArrayList();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (Iterator it = list.iterator(); it.hasNext();) {
String str = (String) it.next();
System.out.println(str);
}

  上面是一段很平常的代码,在一个List集合加入一些字符串,然后再用一个遍历循环把它打印出来。“String str = (String) it.next()”这一句我们可以看到List取出值都是Object,所以我们要得String型,还要做一个类型转换,真是麻烦。更麻烦的是list.add(Object obj)的参数是Object类型,所以如果我们一不小心把list.add("cccc");写成list.add(new Integer(76));程序在循环打印的类型转换中就会出错。

  问题:我们能不能让add方法只认String型呢?
回答:可以!用JDK5.0的泛型。

三、泛型后的幸福生活

  JAVA有了泛型后,就象十年的老光棍讨了老婆,那个好处自不待言。我们来看看上面的例子改成泛型的写法是怎么样的:

        List<String> list = new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (Iterator<String> it = list.iterator(); it.hasNext();) {
String str=it.next();
System.out.println(str);
}

  看到差别了吗?泛型其实很简单,就是在定义类型的后面加上"<类型>"这样子的声明就行了,它主要还有以下差别:

  • list.add方法只能接受String类型。list.add(new Integer(76))这样的语句不需要运行程序,在编译时就会检查通不过。
  • it.next()的返回值不再是Object,而变成了String

  当然我们其实在循环部份也可以象下面这么写,是不是简洁了很多呢 :-)

        List<String> list = new ArrayList<String>();
list.add("aaaa");
list.add("bbbb");
list.add("cccc");
        for (String str : list) {
System.out.println(str);
}

  当然需要说明的是,List不仅可以List<String>,也可以是List<Integer>等等其他任何类型。

四、更深入了解泛型

(1)层层推进的泛型声明

  “List<List> list;”表示什么呢?就是只接收List型的参数,比如:

        List<List> list = new ArrayList<List>();
list.add(new ArrayList());
list.add(new Vector());
list.add(new LinkedList());

  这里要注意List是接口,ArrayList、Vector、LinkedList都是这一接口下的实现类。下面这个有点怪异了,“List<List<String>> list;”表示它只接受List型的参数,而且这种List型的参数又是只是只接受String型,有点层层推进的味道在里面了。

        List<List<String>> list = new ArrayList<List<String>>();
list.add(new ArrayList<String>());
list.add(new Vector<String>());
list.add(new LinkedList<String>());

(2)使用泛型上限通通配符:extends

  这里要着重强调一点:变量的泛型声明和方法的参数的泛型声明有很大差别。

  变量声明成某类型,同时也可以接受它的子类。比如说Integer、Long、Float都是抽象类Number的子类,所以下面的代码一点问题也没有:

        List<Number> list = new ArrayList<Number>();
list.add(new Integer(1));
list.add(new Long(1));
list.add(new Float(1.2));

  但如果换成方法参数的泛型声明则要严格得多了:子类也是不行的。比如下面的代码就是错误的,因为printList参数只接受Number值的List,就是是Number子类的Integer值的List也不行。

    public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(new Integer(1));
list.add(new Integer(2));
printList(list);
}

private static void printList(List<Number> list){
for (Number num : list) {
System.out.println(num);
}
}

 上面代码修改的方法有两个,如下

修改方法一:改变量的泛型声明
将 List<Integer> list = new ArrayList<Integer>();
改为 List<Number> list = new ArrayList<Number>();

修改方法二:用界限通配符改方法参数的泛型声明
将 printList(List<Number> list)
改为 printList(List<? extends Number> list)
说明:extends 的含义就是表示参数可以接受Number型的子类。

(3)使用泛型下限通通配符:super

    在上限就有下限,下限行就是super,用法和extends一样,含义则和extends相反。比如printList(List<? super Integer> list)表示参数可以接受Integer型及Integer型的超类,即Number了,当然也包括Object这个顶级类。

(4)配置符:?

  ?表示可以接受任何类型,不过我觉得它用得不多,因为printList(List<?> list)和printList(List list)的作用是一样的。

五、创建一个支持泛型的类

(1)创建一个泛型的类

public class Point<T> {
T x;
T y;
    public T getX() {
return x;
}
    public T getY() {
return y;
}
    public void setX(T x) {
this.x = x;
}
    public void setY(T y) {
this.y = y;
}
}

  使用这个类的代码如下:

        Point<Integer> p = new Point<Integer>();
p.setX(new Integer(1));
p.setY(new Integer(2));

Point<String> b = new Point<String>();
b.setX("1");
b.setY("2");

  说明:在Point<T>的定义中,T并非关键字,你也可以这样定义Point<ABC>,当然一般还是写T吧,简单也规范。

(2)泛型类的继承与实现

  java.util.Comparator类是JDK里用来排序的,其源代码如下:

package java.util;
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}

   一个实现此接口的类如下:

    public class MyComparator<T> implements Comparator<ObjectInstance> {
public int compare(ObjectInstance o1, ObjectInstance o2) {
String s1 = o1.getObjectName().getCanonicalName();
String s2 = o2.getObjectName().getCanonicalName();
return s1.compareToIgnoreCase(s2);
}
}

  说明:ObjectInstance可能大家还太明白,这是我实际项目中的一段代码(关于JMX的),ObjectInstance全称javax.management.ObjectInstance。MyComparator的使用代码如下:

Set set = ......(省略)
List<ObjectInstance> mbeans = new ArrayList<ObjectInstance>(set);
Collections.sort(mbeans, new MyComparator<ObjectInstance>());

六、最后的感言

  JAVA有了泛型就象老光棍讨了老婆,好处大大的,但和女人一样麻烦也跟着来了:它的严格类型检查,使隐藏的BUG更少。有些地方确实也使代码简洁了,有些地方却会使得代码更复杂。所以运用之妙在于是否用得适当,尽量把泛型往简单里用,别越搞越复杂了。 

参考资料

J2SE 5.0中的泛型 http://www.matrix.org.cn/resource/article/43/43634_java_generics.html

作者简介

陈刚,广西桂林人,著作有《Eclipse从入门到精通》
您可以通过其博客了解更多信息和文章:http://www.ChenGang.com.cn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/256095.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

QT5.14.2基于PCL1.11.1显示点云(基于Windows VS2019开发环境)

文章目录一、安装1.1 PCL安装1.2 QT安装1.3 VTK编译二、程序配置1. 基于mscv创建QT的程序2. 配置QT工程文件和依赖项3. 编写点云显示的小程序总结一、安装 1.1 PCL安装 PCL1.11.1库的安装网上教程很多&#xff0c;推荐一个很好的教程&#xff1a; Win10 系统下 VisualStudio2…

Spring学习笔记—最小化Spring XML配置

自动装配(autowiring)有助于减少甚至消除配置<property>元素和<constructor-arg>元素&#xff0c;让Spring自动识别如何装配Bean的依赖关系。 自动检测(autodiscovery)比自动装配更进了一步&#xff0c;让Spring能够自动识别哪些类需要被配置成Spring Bean&#xf…

【数据结构】——快速排序

目录 一、代码 二、复杂度&#xff1a;O(nlog(n)) 三、快速排序的劣势 视频参考链接&#xff1a;https://www.bilibili.com/video/BV1mp4y1D7UP?p17 一、代码 思想&#xff1a;假设是对一个list进行排序 1、选取第一个元素作为p元素&#xff1b; 2、将p元素归位&#xff0…

读取数据库信息构建视图字段的备注信息,方便程序代码生成

在很多情况下&#xff0c;我们开发都需要有一个快速的代码生成工具用来提高开发效率&#xff0c;代码生成工具很多信息都是读取数据库的表、视图等元数据进行对象表信息的完善&#xff0c;有了这些信息&#xff0c;我们就可以在普通的实体类代码里面添加属性字段的中文注释&…

Ubuntu DNS bind9 配置

下面的配置就是实现解析test.zp.com到不同的IP地址 安装dns server软件包$ apt-get install bind9 配置dns配置文件的路径在/etc/bind路径下面添加一个zone$ /etc/bind# vim /etc/bind/named.conf.local 添加下面&#xff0c;语法可以参照/etc/bind/zones.rfc1918中的语法添加&…

微博分享错误

昨天再做这块的时候&#xff0c;不知怎么的点击之后什么反应都没有&#xff0c;程序也没有崩&#xff0c;日志倒是输出了这个错误 解决办法&#xff1a;打开你写分享的代码跟API文档对比一下创建文本、图片或者网页的时候是不是少写了那个属性&#xff0c;我这里是在创建网页的…

C++总结笔记(十二)—— 智能指针

文章目录前言一、智能指针是什么&#xff1f;二、示例总结前言 C对于内存管理的要求很高&#xff0c;如果不及时释放对象内存&#xff0c;就可能会发生内存泄露或野指针等情况&#xff0c;鉴于这种情况&#xff0c;C11提出了智能指针的概念。 一、智能指针是什么&#xff1f;…

代码生成工具之界面快速生成

界面开发&#xff0c;无论对于Web开发&#xff0c;还是Winform开发&#xff0c;都需要耗费一定的时间&#xff0c;特别对于一个数据库字段比较多的界面&#xff0c;一般就需要在编辑界面上摆的更多的控件来做数据显示&#xff0c;每次碰到这个&#xff0c;都有点头痛&#xff0…

javascript - 封装原生js实现ajax

1 /*2 * ajax方法3 */4 var Ajax function() {5 var that this;6 //创建异步请求对象方法7 that.createXHR function() {8 if(window.XMLHttpRequ…

QT对象树、信号和槽机制

文章目录一 、对象树是什么&#xff1f;二、信号和槽的基本概念2.1 信号2.2 槽2.3 松散耦合2.4 特点三、示例总结一 、对象树是什么&#xff1f; 对象树是由父类和若干子类对象组成&#xff0c;而子类也可以由若干孙类。 QT中的对象树是以QObject为起始父类来完成树的构建的&a…

【数据结构】——归并排序

目录 一、代码 二、随笔 一、代码 归并排序的主要思路&#xff1a;将两个有序的子列表归并为一个有序的大列表 #归并函数&#xff0c;假设li是由左右两个有序的子列表组成,假设两个子列表都是从小到大排好序的列表 def merge(li,low,mid,high)::param li: 由左右两个有序的子列…

开发发布npm module包

开发发布npm module包 问题 在项目开发过程中&#xff0c;每当进入一个新的业务项目&#xff0c;从零开始搭建一套前端项目结构是一件让人头疼的事情&#xff0c;就要重新复制一个上一个项目的前端框架和组件代码库。其中很多功能的模块组件都要重复拷贝&#xff0c;可以统一将…

如何使用ATS提高应用的安全性

App Transport Security&#xff0c;简短的说就是ATS&#xff0c;是iOS9和OS X El Capitan的一个新特性。App Transport Security 的目标是提高Apple 操作系统的安全性以及在此操作系统上运行的任何应用的安全性。 基于HTTP传输数据的网络请求都是明文。开启App Transport Secu…

手机客户端测试考虑的点

手机客户端测试考虑点总结 版权声明&#xff1a;本文为博主原创文章&#xff0c;未经博主允许不得转载。 此文未本人工作中的总结&#xff0c;特此总结。 异常场景&#xff1a; 网络异常&#xff0c;服务器异常&#xff0c;接口异常或参考参数篡改&#xff0c;断电&#xff0c;…

NMS(非极大值抑制)算法详解与示例

一、NMS是什么&#xff1f; NMS&#xff08;non maximum suppression&#xff09;即非极大值抑制&#xff0c;广泛应用于传统的特征提取和深度学习的目标检测算法中。 NMS原理是通过筛选出局部极大值得到最优解。 在2维边缘提取中体现在提取边缘轮廓后将一些梯度方向变化率较小…

【数据结构】——冒泡排序、插入排序、选择排序

# 冒泡排序&#xff0c;复杂度为O(n^2) def bubble_sorted(li:list)->list:for i in range(len(li)):# 第几趟exchanged False# 这个是为了防止多余的遍历&#xff0c;如果前面的元素已经是排序好的&#xff0c;那就不需要再进行比较了&#xff0c;减少运行时间for j in ra…

【转载】ASP.NET应用程序与页面生命周期

在本文中&#xff0c;我们将了解不同的事件&#xff0c;ASP.NET 应用程序的生命周期以浏览器向 Web 服务器&#xff08;对于 ASP.NET 应用程序&#xff0c;通常为 IIS&#xff09;发送请求为起点&#xff0c;直至将请求结果返回至浏览器结束。在这个过程中&#xff0c;首先我们…

基于PCL的ICP及其变种算法实现

文章目录前言一、ICP算法基础1.1 提取待匹配点对1.2 计算旋转平移矩阵1.3 计算变换后的点和目标点之间的偏差二、ICP算法变种2.1 PLICP2.2 PointToPlane ICP2.3 NICP2.4 LM_ICP三、程序示例1. 传统方法2. PointToPlane ICP总结前言 ICP&#xff08;Iterative Closest Point&am…

python 计算器

--coding:utf-8-- from Tkinter import * 创建横条型框架 def frame(root, side): w Frame(root) w.pack(side side, expand YES, fill BOTH) return w 创建按钮 def button(root, side, text, command None): w Button(root, text text, command command) w.pack(side…

最长公共子序列(LCS)

注意最长公共子串&#xff08;Longest CommonSubstring&#xff09;和最长公共子序列&#xff08;LongestCommon Subsequence, LCS&#xff09;的区别&#xff1a;子串&#xff08;Substring&#xff09;是串的一个连续的部分&#xff0c;子序列&#xff08;Subsequence&#x…