一、为什么使用泛型

     复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用。

     安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换。这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查。

二、自定义泛型

java中自定义泛型分为三种:泛型类、泛型接口、泛型方法。

下面使用一个案例演示泛型类、泛型方法,泛型接口类似,所以不再演示。

// 自定义泛型类
public class Generic<T>
{
    private T second;
    public void setSecond(T newValue)
    {
        second = newValue;
    }
    // 自定义泛型方法
    public static <W> void printValue(W obj)
    {
        System.out.println(obj.toString());
    }
   
    @Override
    public String toString()
    {
        return second.toString();
    }
   
    public static void main(String[] args)
    {
        //
        Generic<String> g = new Generic<String>();
        g.setSecond("zhang");
        System.out.println(g);
       
        // 使用泛型方法
        Generic.printValue(45);
        Generic.printValue("hello");
    }
}

泛型方法可以在普遍类中定义,也可以在泛型类中定义。

三、java泛型的特性

1、擦除

       java中的泛型是伪泛型,因为在编译期间,所有的泛型信息都会被擦除,而只保留原始类型。比如,代码List<Double>和List<String>在经过编译后,都会变成List类型。
       为什么会出现这种情况呢?这跟java的虚拟机有莫大的关系。java虚拟机没有泛型类型对象-----所有对象都属于普通类。由于在java1.5之前没有泛型,那之前没有泛型的代码怎么与有泛型的代码共存了,为了兼容性,java虚拟机采用统一的普通类。
下面使用代码,体现类型擦除。
public static void main(String[] args)
{
    ArrayList<String> arrayList1=new ArrayList<String>(); 
    arrayList1.add("abc"); 
    ArrayList<Double> arrayList2=new ArrayList<Double>(); 
    arrayList2.add(666.666); 
    System.out.println(arrayList1.getClass()==arrayList2.getClass()); 
}
输出结果:

true

2、补偿

public static void main(String[] args)
{
    ArrayList<String> arrayList1=new ArrayList<String>(); 
    arrayList1.add("abc"); 
    String str = arrayList1.get(0);    // 编译正常
    int str2 = arrayList1.get(0);      // 编译报错  
}
arrayList1.get(0);
编译过后,泛型会被擦除,arrayList1.get(0)返回Object类型。但是由于java的补偿机制,因此编译器会自动的插入String的强制类型转换。由于int类型的str2不能接收经过强制转换的String类型,因而编译报错。
 

四、java泛型的约束

1、不能用基本类型实例化类型参数
比如:错误-->Arraylist<double>; 正确-->Arraylist<Double>
2、运行时类型查询只适用于原始类型
3、不能创建参数化类型的数组
4、不能实例化类型变量
5、泛型类的静态上下文中类型变量无效
比如:private static T single; // ERROR
6、不能抛出或捕获泛型类的实例

五、通配符类型

1、限定上界通配符

比如:List<? extends Animal>,表示任何泛型List类型,它的类型参数是Animal类及子类,List<Animal>、List<Cat>、List<Dog>都是List<? extends Animal>子类型。
public static void main(String[] args)
{
    List<? extends Animate> animates = new ArrayList<Animate>();         // OK
    List<? extends Animate> animates1 = new ArrayList<Cat>();            // OK
    List<Animate> animates2 = new ArrayList<Animate>();                  // OK
    List<Animate> animates3 = new ArrayList<Cat>();                      // compile-time error       
}
其实,我们可以将List<? extends Animate> animates 看做是List<Animate>、List<Cat>等的集合。
归纳:假如给定的泛型类型为G,两个具体的泛型参数X、Y,当Y是X的子类时(Y extends X)
  • G<? extends Y> 是 G<? extends X>的子类型(如List<? extends Cat> 是 List<? extends Animal>的子类型)。
  • G<X> 是 G<? extends X>的子类型(如List<Animal> 是 List<? extends Animal>的子类型)
  • G<?> 与 G<? extends Object>等同,如List<?> 与List<? extends Objext>等同

学到这里,可能会遇到一些疑惑的地方,或者说事理解不透的地方,先观察如下两段代码片段,判断一下其是否可行??
List<? extends Animal> animal = new ArrayList<>();
animal.add(new Animal());
animal.add(new Cat());

上面的两个add操作都不能通过编译。为什么呢?由于List:add(E e)加入泛型变成List<? extends Animal>:add(? extends Animal e),? extends Animal参数类型无法确定,可以是Animal、Cat等,所以为了保护其类型的一致性,因此不允许向list对象中添加任意对象,除了null。

 
注意:上界限定一般用在:? extends T get()方法上(读数据操作)
 

2、限定下界通配符

比如:List<? super Cat>,这个通配符限制为Cat的所有超类型(包括本类)。
它的归纳方法与上界通配符相似,这里就不啰嗦了。
看下面代码:
List<? super Animate> animates = new ArrayList<>();    
animates.add(new Animate());
animates.add(new Cat());
上述代码编译通过,编译器不知道add方法的确切类型,但是可以用任意Animal对象(或子类型对象)。
 
注意:下界通配符通常用于:set(? extends T>)方法上(写入数据操作)

3、无限定通配符

比如:List<?>,当类型不确定时,才使用,该通配符较少使用。
 
关于上下界限定通配符,建议参考:《编写高质量代码:改善java程序的151个建议》中建议96:不同的场景使用不同的泛型通配符
 
参考

1、Java 泛型通配符?解惑

java 泛型 窜讲的更多相关文章

  1. 第11讲-Java泛型和文件操作

    1.知识点 1.1.课程回顾 1.2.本章重点 1.2.1.泛型 1.2.2.文件操作 2.具体内容 2.1.Java泛型 2.1.1.为什么需要泛型 我们发现在List中,底层是Object[ ]数 ...

  2. 初识java泛型

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

  3. Java泛型学习笔记 - (七)浅析泛型中通配符的使用

    一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List< ...

  4. Java泛型-类型擦除

    一.概述 Java泛型在使用过程有诸多的问题,如不存在List<String>.class, List<Integer>不能赋值给List<Number>(不可协变 ...

  5. Java 泛型,了解这些就够用了。

    此文目录: Java泛型是什么? 通常的泛型的写法示例 类型擦除 为什么要使用Java泛型 通过示例了解PECS原则 一.Java泛型是什么? 官方定义 泛型是Java SE 1.5的新特性,泛型的本 ...

  6. Java泛型总结

    1. 什么是泛型?泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的 ...

  7. Java泛型:类型擦除

    类型擦除 代码片段一 Class c1 = new ArrayList<Integer>().getClass(); Class c2 = new ArrayList<String& ...

  8. 转:有关Java泛型的类型擦除(type erasing)

    转载自:拈花微笑 自从Java 5引入泛型之后,Java与C++对于泛型不同的实现的优劣便一直是饭后的谈资.在我之前的很多training中,当讲到Java泛型时总是会和C++的实现比较,一般得出的结 ...

  9. JAVA泛型那些事儿

    本篇内容源于本人一个好友sgpro提供的java学习例子,现拿出来给大家分享. 此例子非常直观的通过代码讲解了java泛型的用法和好处,是笔者一直珍藏的最好的泛型学习笔记. 一.面向过程的时代 我们先 ...

随机推荐

  1. OC/Swift第三方添加出错解决方法

    (未经同意,不得转载!) ------------------------华丽分割线-----------------------

  2. Codeforces Round #324 (Div. 2) C. Marina and Vasya 贪心

    C. Marina and Vasya Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/584/pr ...

  3. Java自学成长路线(转载)

    JAVA自学之路 一:学会选择  决心做软件的,大多数人选的是java,或是.net,也有一些选择了手机.嵌入式.游戏.3G.测试等.  JAVA是一种平台,也是一种程序设计语言,如何学好程序设计不仅 ...

  4. Mysql数据库导出压缩并保存到指定位置备份脚本

    #!/bin/bashbackdir=/home/shaowei/dbbakdbuser='dbusername'dbpass='dbpasswd'dblist=$(ls -p /var/lib/my ...

  5. Android(java)学习笔记86:案例短信发送器

    1.一般我们第一步都是先创建这个main.xml布局文件,这是良好的习惯: <?xml version="1.0" encoding="utf-8"?&g ...

  6. 如何解决linux(ubuntu/CENTOS)中gedit中文乱码的问题

    http://jingyan.baidu.com/article/1709ad80a443c54634c4f09c.html 同时按键盘的Alt 和 F2,就可以打开“运行程序”对话框,这个功能类似于 ...

  7. FastStone Capture 注册码 序列号

    用户名:c1ikm 注册码:AXMQX-RMMMJ-DBHHF-WIHTV 或 AXOQS-RRMGS-ODAQO-APHUU

  8. PHP 点滴疑惑

    在数据库中,字段为NULL,可以使用empty()进行判断 <?php $CONFIG['hostname'] = 'localhost'; $CONFIG['username'] = 'roo ...

  9. Visual Studio 2015中的常用调试技巧分享

    .NET 技术交流群:337901356 欢迎您的加入! 为什么要学习调试? 调试(Debug)是作为一个程序员必须要学会的东西,学会调试可以极大的提高开发效率,排错时间,很多人不喜欢调试,但我认为这 ...

  10. 什么是CS和BS结构,两种结构的区别

    什么是CS和BS结构,两种结构的区别 什么是C/S和B/S结构?         C/S又称Client/Server或客户/服务器模式.服务器通常采用高性能的PC.工作站或小型机,并采用大型数据库系 ...