Java泛型解析(01):认识泛型
What
     Java从1.0版本号到如今的8。中间Java5中发生了一个非常重要的变化,那就是泛型机制的引入。Java5引入了泛型,主要还是为了满足在1999年指定的最早Java规范之中的一个。经过了5年左右的时间,专家组定义了一套泛型规范,实现后通过測试投入到使用。

所以说泛型是Java5以后才有的,欲知详情,继续往下看。

Why
     换个角度想。Java5引入泛型。必然是它能带来优点,否则牛气的Java专家project师就要遭到吐槽了。

我们来吐槽一下没有泛型的程序是怎么写的。

[code01]
           ArrayList al = new ArrayList();
al.add("ysjian001");
al.add(1);
al.add(new Object());

这段代码看似功能强大。为什么呢?由于它似乎可以往集合加入各种类型的对象(int 类型会被装箱成 Integer对象类型),貌似一些老程序猿也倾向于这么去做,并且他们可以理直气壮的告诉我理由:我这么做想存什么就存什么!先不否定这样的说法,让我们继续,看看以下代码。

[code02]
            // 获取值的时候必须进行强制转换。然后调用相应对象的方法
String first = (String) al.get(0);

往集合里面存值就是为了后期取出来用的。而不是System.out.println(first),这里就产生了一个强制转换的问题,而往往这样的类型的强制转换在编译器是同意通过的,而敲代码的人们会犯下无意间的错误,错误的进行了强制转换,导致程序执行失败。

     强制类型转换导致的程序执行失败的原因是没有在编译器对类型进行控制。看看code01调用ArrayList对象的add方法,不论什么类型都是能够加入进行的,编译器无法进行错误检验。埋下了安全隐患,比如:
[code03]

          ArrayList al = new ArrayList();
// 无法进行错误检查,File对象能够加入进去,编译器和执行期都能够通过
al.add(new File());
String first = (String) al.get(0); // 类型转换失败导致执行失败
没有泛型的程序面临两个问题:
     1.编译器无法进行类型检查,能够向集合中加入随意类型的对象。
     2.取值时类型转换失败导致程序执行失败。

没有泛型的程序导致的后果:
     1.程序的可读性有所减少。由于程序猿能够不受限制往集合中加入随意对象。
     2.程序的安全性遭到质疑,类型转换失败将导致程序执行失败。


     Java5泛型提供了一个更好的解决方式:类型參数(type parameters)。使用泛型的程序改善上述代码例如以下:
[code04]

          ArrayList<String> al = new ArrayList<String>();
al.add( "ysjian001");
// al.add(new Thread()); // 定义了String类型參数,加入File对象会报错
String first = al.get(0);// 使用泛型后取值不用进行类型转换
     问:到这里。通过前后对照。泛型的优点是不是非常清楚了呢?为什么用泛型呢?
     答:由于出现编译错误比类在执行时出现强制类型转换异常要好得多,泛型的优点在于提高了程序的可读性和安全性。这也值程序设计的宗旨。

Who
     使用泛型类是一件非常轻松的事,集合框架中的类都是泛型类。用起来非常方便。

有人会想类型限制我们为什么不直接用数组呢?这个问题就好像问为什么集合优于数组。数组是固定的,而集合是能够自己主动扩展的。

另外在实际中。实现一个泛型事实上并非那么easy。看一个员工和经理继承结构:

[code05]

          public class Employee {
//......
}
public class Manager extends Employee {
// ......
}
当我们创建并使用一个员工的集合的时候,使用起来并不复杂:
[code06]

          ArrayList<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee()); // 能够加入员工
employees.add( new Manager()); // 能够加入经理,由于经理也是员工
     上述的使用毫无问题的,由于Manager is a Employee。典型的继承关系。可是当反过来的时候。可能不那么顺利了,比方:
[code07]

          ArrayList<Manager> employees = new ArrayList<Manager>();
employees.add(new Manager()); // 加入经理是正常的操作
// employees.add(new Employee()); // 此时不能够加入Employee
上面的代码就有问题了。而这样的需求又不是不存在,那么怎么办呢?不要着急,聪明的Java设计者发明了一个独具创新的新概念,通配符类型(wildcard type)。这里仅仅须要知道这个概念。后面会具体解说。

     大多数应用程序猿对泛型的熟练程度只停留在使用泛型上。像集合类中的List、Set和Map这些泛型集合用的非常多,他们不必考虑这些泛型集合的工作方式和原理。

那么当把不同的泛型类混合在一起使用时,或者对Java5之前的遗留代码进行衔接时,可能会看到含糊不清的的错误消息。

这样一来。程序猿就须要学习Java泛型来解决这个问题了,而不是在程序中胡乱推測了。终于,部分程序猿可能想要实现自己的泛型类和泛型方法。

     提炼出泛型程序设计的三种熟练程度就是:
     1.只使用泛型。
     2.学习泛型解决一些问题。
     3.掌握泛型,实现自己的泛型。

How
     怎样使用泛型听起来是一件非常easy的事情,由于Sun公司的那些project师已经做了非常大努力。而需求总是会略微苛刻一点的。须要解决由于缺乏类型參数模糊不清的问题,或者我们有必要实现自己的泛型来满足业务需求,所以学习和掌握泛型是非常有必要的。
泛型类:
     从简单的入手。定义一个泛型类:
[code08]

     public class Couple<T> {
private T wife ;
private T husband ; public Couple(T wife, T husband) {
this.wife = wife;
this.husband = husband;
}
public void setWife(T wife) {this. wife = wife;}
public void setHusband(T husband) {this. husband = husband;} public T getWife() {return wife;}
public T getHusband() {return husband;}
}
     Couple 夫妇类引入一个类型參数T。注意了,类型參数是用尖括号(< >)括起来的。而且放在类名后面,code08中的Couple类有一个类型參数。能够定义多个类型參数,格式为<T, K, V>, 类型參数能够用来定义方法的返回类型、參数类型、以及定义域或局部变量,如以下代码
[code09]

          public class Couple<T, K, V> {......} // 多个类型參数用逗号隔开
private T wife ; // 类型參数定义域
public T getWife() {return wife;}// 类型參数定义方法返回的类型
     在Java类库中,类型变量通经常使用大写的字母表示,E表示集合的元素类型。K和V分别表示映射表的keyword和值的类型,T(U或S)表示随意类型。
     一个简单的泛型类Couple定义好了,怎么使用呢?别着急。我们使用这个Couple类时指定一个详细的參数类型。如Person类:Couple<Person>
[code10]

          Couple<Person>(Person,Person);
setWife(Person);
setHusband(Person);
Person getWife();
Person getHusband();
     code10中的代码是使用Person类型作为參数类型后。Couple类型的变化,注意这里     不是真正的变化成这样了。而是我们使用的时候这么理解,至于为什么呢?在后面会具体解说擦除。

泛型方法:
     定义了泛型类有什么优点呢?通过前面的样例,这个泛型类能够让使用该类的用户在使用的时候指定才详细的类型。提高了一定的灵活性。那么看看泛型方法的定义是怎么回事?
[code11]

     public class GenericMethod {
public static <T> T getFirstValue(T[] values) {
return values[0];
}
}
     从已经学习的泛型类加上code11中的泛型方法的定义中总结一条,就是全部泛型都必须先以<T>(多个类型參数用逗号隔开。如<K, V>)的形式进行定义,这是必要的前提。回过头来看看上述泛型方法的定义,给方法定义了一个类型參数T,指定方法的返回值为T。方法的參数为T类型的数组。
     对方法的调用就比較直观了
[code12]

          String[] values = { "JavaSE","CoreJava" ,"EffectiveJava"};
String firstValue = GenericMethod.<String>getFirstValue(values);
     咋看调用还是有点复杂,为什么要在方法调用前用<String>呢?事实上这不是必要的。当我们将String[]类型的values传给方法时,编译器足以推断T的详细类型为String类型,所以<String>能够省略掉。

[code13]

          String firstValue = GenericMethod.getFirstValue(values);
总结:
     这一节里,对泛型有了一个总体的认识,知道它是什么?为什么要用它?谁会用它?以及怎样使用它?通过了泛型类和泛型方法的实践,感受了怎样实现自己的泛型。后面一节,将对泛型中通配符进行解说,以及虚拟机对泛型类和泛型方法的擦除。


Java泛型解析(03):虚拟机运行泛型代码

Java泛型解析(04):约束和局限性



=====【感谢亲阅读寻常心的文章。亲若认为此文有帮助。顶一顶亲的支持将给我前进的动力】=====


Java泛型解析(01):认识泛型的更多相关文章

  1. Java泛型解析(03):虚拟机运行泛型代码

    Java泛型解析(03):虚拟机运行泛型代码      Java虚拟机是不存在泛型类型对象的,全部的对象都属于普通类,甚至在泛型实现的早起版本号中,可以将使用泛型的程序编译为在1.0虚拟机上可以执行的 ...

  2. Java泛型解析(04):约束和局限性

    Java泛型解析(04):约束和局限性           前两节.认识和学习了泛型的限定以及通配符.刚開始学习的人可能须要一些时间去体会到泛型程序设计的优点和力量,特别是想成为库程序猿的同学就须要下 ...

  3. Java泛型解析(02):通配符限定

    Java泛型解析(02):通配符限定      考虑一个这种场景.计算数组中的最大元素. [code01] public class ArrayUtil { public static <T&g ...

  4. Java编程的逻辑 (36) - 泛型 (中) - 解析通配符

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...

  5. Java泛型解析

    1. 概述    在引入范型之前,Java类型分为原始类型.复杂类型,其中复杂类型分为数组和类.引入范型后,一个复杂类型就可以在细分成更多的类型. 例如原先的类型List,现在在细分成List< ...

  6. Java中泛型的详细解析,深入分析泛型的使用方式

    泛型的基本概念 泛型: 参数化类型 参数: 定义方法时有形参 调用方法时传递实参 参数化类型: 将类型由原来的具体的类型参数化,类似方法中的变量参数 类型定义成参数形式, 可以称为类型形参 在使用或者 ...

  7. 使用GSON和泛型解析约定格式的JSON串(转)

    时间紧张,先记一笔,后续优化与完善. 解决的问题: 使用GSON和泛型解析约定格式的JSON串. 背景介绍: 1.使用GSON来进行JSON串与java代码的互相转换. 2.JSON的格式如下三种: ...

  8. Java 8 新特性之泛型的类型推导

    1. 泛型究竟是什么? 在讨论类型推导(type inference)之前,必须回顾一下什么是泛型(Generic).泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据 ...

  9. 【java基础学习】-【泛型】

    参考以下几位同学的总结来学习: http://www.cnblogs.com/lwbqqyumidi/p/3837629.html#!comments http://www.weixueyuan.ne ...

随机推荐

  1. P1044 栈

    题目背景 栈是计算机中经典的数据结构,简单的说,栈就是限制在一端进行插入删除操作的线性表. 栈有两种最重要的操作,即pop(从栈顶弹出一个元素)和push(将一个元素进栈). 栈的重要性不言自明,任何 ...

  2. spark web ui

    spark UI 界面:http://www.cnblogs.com/xing901022/p/6445254.html 几个概念的解释:http://blog.csdn.net/jiangwlee/ ...

  3. ubuntu系统nginx+Redis+PHP

    一.安装ngnix apt-get update sudo apt-get install nginx /etc/init.d/nginx start 二.安装php sudo apt-get ins ...

  4. ERwin 正向工程

    1.物理模型带字段备注 COMMENT ON 将模型切换至 physical 模式选择 Model ---> Domain Dictionary , 在 tab 标签中,切换至comment 然 ...

  5. UML实例教程 解析UML建模分析与设计

    UML统一建模语言在软件开发过程中非常实用,UMl建模的分析与设计你是否熟悉,这里就通过实例向大家介绍,希望通过本文的学习,你对UML建模的分析与设计方法有一定的了解. 本节向大家介绍一下图书管理系统 ...

  6. (转)淘淘商城系列——使用Spring来管理Redis单机版和集群版

    http://blog.csdn.net/yerenyuan_pku/article/details/72863323 我们知道Jedis在处理Redis的单机版和集群版时是完全不同的,有可能在开发的 ...

  7. 梦想CAD控件com接口扩展数据

    随着CAD应用软件的飞速发展,经常需要保存一些与图形可视性无关的数据,即非图形参数.例如在绘制化验样图中包含品位数据.MxCAD定义了一类参数——实体扩展数据.扩展数据与实体的可视性无关,而是用户根据 ...

  8. ThinkPHP---拓展之jQuery的ajax

    [前言] 用Sublime开发时,推荐下载一个jQuery插件,可以智能化创建基本函数格式,支持自动生成,可以提高开发效率 (1)jQuery里ajax方法有几个? 答:有4个,分别为post.get ...

  9. Python之实例属性和类属性

    参考原文 廖雪峰Python 实例属性和类属性 在前面已经说过由于Python是动态语言,可以根据类的实例绑定任何的属性. 给实例绑定属性的方法是通过实例变量,或者self变量绑定的: class S ...

  10. angular中处理多个异步请求的方法汇总

    在实际业务中经常需要等待几个请求完成后再进行下一步操作.但angularjs中$http不支持同步的请求. 解决方法一: $http多层嵌套 $http.get('url1').success(fun ...