对于我们java中的泛型,可能很多人知道怎么使用并且使用的还不错,但是我认为想要恰到好处的使用泛型,还是需要深入的了解一下它的各种概念和内部原理。本文将尽可能的囊括java泛型中的重要的概念。主要内容如下:

  • 泛型的定义及为什么要使用泛型
  • 定义一个简单的泛型类
  • 定义一个简单的泛型方法
  • 类型参数的限定
  • 泛型内部实现的基本原理
  • 泛型通配符(难点)
  • 泛型的其他实现细节

    一、何谓泛型
         泛型程序设计意味着编写的代码可以被不同中类型的对象重用。例如:MyList<T>,MyList<Integer>是一种类型,MyList<String>也是一种类型,但是使用的代码块都是MyList<T>,这也就是java中引入泛型的一种原因:可以增强代码的复用性,当然这种限定死类型的方式也会使得代码的安全性和可读性更高。

    二、一个简单的泛型类
         先看一个完整的泛型类:

  1. /*一个简单的泛型类的声明如下*/
  2. public class Pair<T> {
  3. private T a;
  4. private T b;
  5. public Pair(T a, T b){
  6. this.a = a;
  7. this.b = b;
  8. }
  9. }

     由此可以看出来,泛型类型和普通类型的区别主要在于:类名之后多了个<T>,并且实例域类型可以不是具体的类型而是不确定的T类型。其中,我们管T叫做类型变量,类型变量一般使用大写字母表示并且很短(在java中使用E表示集合的元素类型,K和V分别表示关键字和值的类型)。
     使用具体的类型来替换类型变量的过程我们叫做实例化泛型类型。例如:Pair<Integer>,<Double>等。这其中需要注意的是:java中的9中基本类型是不能作为类型变量的,也就是:Pair<int>,是会不允许的。当然,声明一个泛型类时,不局限于一个类型变量,可以由多个类型变量,例如:

  1. /*声明两个类型变量也是可以的*/
  2. public class Pair<T,U> {
  3. private T a;
  4. private U b;
  5. public Pair(T a, U b){
  6. this.a = a;
  7. this.b = b;
  8. }
  9. }
  10. //Pair<String,Integer> p new Pair<>("abc",12);
  11. //创建泛型类实例变量的时候,可以省略类型变量,编译器可以推测出来

三、一个简单的泛型方法
     怎么定义泛型类,我们已经介绍过了,接下来我们一起看看泛型方法是如何定义和调用的。

  1. /*泛型类中定义了一个泛型方法*/
  2. public class Pair<T> {
  3. //声明一个泛型方法
  4. public <T> T getA(T c){
  5. return c;
  6. }
  7. }
  8. /*main函数中调用泛型方法*/
  9. public class Test2 {
  10. public static void main(String[] args){
  11. Pair<Integer> p = new Pair<Integer>(1,2);
  12. //调用泛型方法
  13. System.out.println(p.<Integer>show(10));
  14. }
  15. }

     我们可以看到,声明一个泛型方法:public <T > T getA(T c),<T >放在返回值前面,修饰符后面,T表示返回类型。泛型方法的调用:p.<Integer>show(10),在方法名前面放置类型变量,当然也可以选择省略,当编译器没有足够的信息推测出来时就会报错,那时你再添加也不迟(但是,如果你能减轻计算机的工作的话,想必是可以提高效率的)
     小结一下,泛型类和泛型方法。泛型类中可以声明泛型方法也可以声明普通方法,泛型方法可以出现在泛型类中也可以出现在普通类中,也就是它们之间并没有什么约束关系。

四、类型变量的限定
     前面我们已经知道了什么是类型变量,我们看一段代码:

  1. public class Pair<T> {
  2. public static <T> int myCompare(T a,T b){
  3. return a.compareTo(b);//此处编译不通过
  4. }
  5. }

     我们知道,如果想要使用compareTo方法,就要实现Comparable接口,或者继承实现了此接口的类。此处想要使得程序正确,有两种办法。第一种:使类继承Comparable接口并且实现compareTo方法。第二种:就是使用类型变量限定。如下:

  1. /*限定变量类型*/
  2. public class Pair<T> {
  3. public static <T extends Comparable> int myCompare(T a,T b){
  4. return a.compareTo(b);
  5. }
  6. }

     细心的同学可能已经发现,相比于原来的方法,就是使类型变量继承与Comparable接口。原来的<T >变成了<T extends Comparable>,表示:原来的T可以是任意类型的,而现在的T被限制必须实现了Comparable 接口,就是说,凡是使用此泛型的类都是直接或者间接继承了Comparable 接口并实现其中方法的。所以,一旦我们将T限定了,就不用考虑实现Comparable 接口的事情了,程序的封装性更强了。
     对类型变量的限定可以由多个限定,它们之间使用&分隔,而使用逗号分隔类型变量。看个例子:

  1. <T extends Comparable> //一个类型变量的一个类型限定
  2. <T extends Comparable & Serializable> //一个类型变量的两个类型限定
  3. <T extends ComparableU extends Serializable>//两个类型变量的类型限定

五、泛型实现的基本原理
     讨论了这么多的泛型方法,泛型类以及各种使用技巧,接下来,我们一起看看虚拟机实际执行时是怎么对待我们的泛型的。我们都知道java中有编译器和虚拟机,但实际上我们的泛型在这两者看来是不一样的,也就是说,虚拟机是不认识泛型的,而只有我们强大的编译器是认识泛型的。那他们是怎么实现统一的呢?接下来我们详细来看。
     在java中,无论何时定义了一个泛型,它都会自动生成一个相应的原始类型。我们叫这个过程为:类型擦除。例如下面的代码:

  1. /*这是一段泛型类的代码*/
  2. public class Pair<T> {
  3. private T a;
  4. private T b;
  5. public T getA(){
  6. return this.a;
  7. }
  8. public T getB(){
  9. return this.b;
  10. }
  11. }
  1. 经过类型擦除之后生成原始类型:
  1. public class Pair{
  2. private Object a;
  3. private Object b;
  4. public Object getA(){
  5. return this.a;
  6. }
  7. public Object getB(){
  8. return this.b;
  9. }
  10. }

     经过对比,我们可以得出结论:去除了泛型的标志性符号<>并且所有的T类型都被替换成Object类型了。难道我们的类型擦除就是将所有的未知类型转换为Object类型吗?当然不是,类型擦除是有规则的而不是一味的将未知类型T转换成Object类型的。
     对于有限定的类型变量就将用类型变量的第一个限定类型替换。如:Pair<T extends Comparable & Serializable>,就会选择用Comparable替换所有的T并去除修饰在类后面的泛型符号,生成原始类型。
     对于没有限定类型的类型变量就默认使用Object替换类型变量。例如:Pair<T>就会使用Object替换所有的T类型变量。
     最后小结一下,类型擦除针对是否有类型限定类型,根据不同的状况进行替换生成相应的原始类型供jvm调用。

未完,待续。。。。

令人费解的java泛型的更多相关文章

  1. 解析令人费解的java泛型

    对于我们java中的泛型,可能很多人知道怎么使用并且使用的还不错,但是我认为想要恰到好处的使用泛型,还是需要深入的了解一下它的各种概念和内部原理.本文将尽可能的囊括java泛型中的重要的概念.主要内容 ...

  2. Java泛型的历史

    为什么Java泛型会有当前的缺陷? 之前的章节里已经说明了Java泛型擦除会导致的问题,C++和C#的泛型都是在运行时存在的,难道Java天然不支持“真正的泛型”吗? 事实上,在Java1.5在200 ...

  3. 浅析Java 泛型

    泛型是JavaSE5引入的一个新概念,但是这个概念在编程语言中却是很普遍的一个概念.下面,根据以下内容,我们总结下在Java中使用泛型. 泛型使用的意义 什么是泛型 泛型类 泛型方法 泛型接口 泛型擦 ...

  4. Java:泛型基础

    泛型 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚很多! 解决这种限制的 ...

  5. java泛型基础

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 这种参数类型可以用在类.接口和方法的创建中, 分别称为泛型类.泛型接口.泛型方法.  Ja ...

  6. 使用java泛型设计通用方法

    泛型是Java SE 1.5的新特性, 泛型的本质是参数化类型, 也就是说所操作的数据类型被指定为一个参数. 因此我们可以利用泛型和反射来设计一些通用方法. 现在有2张表, 一张user表和一张stu ...

  7. 关于Java泛型的使用

    在目前我遇到的java项目中,泛型应用的最多的就属集合了.当要从数据库取出多个对象或者说是多条记录时,往往都要使用集合,那么为什么这么使用,或者使用时有什么要注意的地方,请关注以下内容. 感谢Wind ...

  8. 初识java泛型

    1 协变数组类型(covariant array type) 数组的协变性: if A IS-A B then A[] IS-A B[] 也就是说,java中的数组兼容,一个类型的数组兼容他的子类类型 ...

  9. 【Java心得总结四】Java泛型下——万恶的擦除

    一.万恶的擦除 我在自己总结的[Java心得总结三]Java泛型上——初识泛型这篇博文中提到了Java中对泛型擦除的问题,考虑下面代码: import java.util.*; public clas ...

随机推荐

  1. iOS调试-LLDB学习总结

    from:http://www.jianshu.com/p/d6a0a5e39b0e LLDB阐述 LLDB 是一个有着 REPL 的特性和 C++ ,Python 插件的开源调试器.LLDB 绑定在 ...

  2. IOS开发-UI学习-UINavigationController(导航控制器)的使用

    UINavigationController是IOS 中常用的功能,基本用法如下: 1.在AppDelegate.m中添加如下代码: #import "AppDelegate.h" ...

  3. 设置git账号并生成新的ssh(切换电脑用户之后)

    1.设置账号 2.设置邮箱 3.检查确认 4. 5.check-----成功~

  4. java系列--并发

    1.Executor 原博:http://blog.csdn.net/linghu_java/article/details/17123057 2.CountDownLatch()方法 浅析Java中 ...

  5. checkbox、radio控件和文字不对其

    一般使用html控件的时候  单选按钮和复选框的控件和文字不对齐 给input控件加上   style="vertical-align: middle; margin-top: -2px; ...

  6. PHP使用JPG生成GIF动画图片,基于php_imagick_st-Q8.dll

    PHP使用php_imagick_st-Q8.dll类库,把JPG图片连接生成GIF动画图片,需要事先下载好php_imagick_st-Q8.dll,文件,并配置php.ini文件,启用php_im ...

  7. PHP之Mysql常用SQL语句示例的深入分析

    1.插入数据insert into表名(列名1,列名2,列名..) values(值1,值2,值...); insert into product(name, price, pic_path) val ...

  8. oracle 查询哪些表分区

    如果查询当前用户下得分区表:select * from user_tables where partitioned='YES'如果要查询整个数据库中的分区表:select * from dba_tab ...

  9. underscore 1.7.0 api

    它是这个问题的答案:“如果我在一个空白的HTML页面前坐下, 并希望立即开始工作, 我需要什么?“ http://www.css88.com/doc/underscore/#

  10. xmlns:xsi ——是指xml文件遵守xml规范,xsi全名:xml schema instance

    http://blog.sina.com.cn/s/blog_4b6f8d150100nx3e.html http://blog.csdn.net/iaiti/article/details/4226 ...