一、为什么使用泛型

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

安全性:在对类型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 泛型通配符?解惑

转载于:https://www.cnblogs.com/aoguren/p/5744923.html

java 泛型 窜讲相关推荐

  1. 用了这么多年的 Java 泛型,你对它到底有多了解?|原创

    作为一个 Java 程序员,日常编程早就离不开泛型.泛型自从 JDK1.5 引进之后,真的非常提高生产力.一个简单的泛型 T,寥寥几行代码, 就可以让我们在使用过程中动态替换成任何想要的类型,再也不用 ...

  2. 深入Java泛型(三):泛型的上下边界

    泛型的命名规范 为了更好地去理解泛型,我们也需要去理解java泛型的命名规范. 为了与java关键字区别开来,java泛型参数只是使用一个大写字母来定义.各种常用泛型参数的意义如下: E - Elem ...

  3. 【Java 泛型】使用上下边界通配符解决泛型擦除问题

    文章目录 前言 一.使用上边界通配符示例 二.分析字节码的附加信息 前言 上一篇博客 [Java 泛型]泛型用法 ( 泛型编译期擦除 | 上界通配符 <? extends T> | 下界通 ...

  4. Json反序列化与Java泛型

    Java的JSON库有很多,本文分析google的Gson和alibaba的fastjson,在Java泛型场景反序列化的一些有意思的行为.考虑下面的json字符串: ["214748364 ...

  5. Java泛型的类型擦除

    写在前面:最近在看泛型,研究泛型的过程中,发现了一个比较令我意外的情况,Java中的泛型基本上都是在编译器这个层次来实现的.在生成的Java字节代码中是不包含泛型中的类型信息的.使用泛型的时候加上的类 ...

  6. Java泛型:类型擦除

    前情回顾 Java泛型:泛型类.泛型接口和泛型方法 类型擦除 代码片段一 1 2 3 4 5 6 7 Class c1 = new ArrayList<Integer>().getClas ...

  7. 大白话说Java泛型:入门、使用、原理

    文章首发于[博客园-陈树义],点击跳转到原文<大白话说Java泛型:入门.使用.原理> 远在 JDK 1.4 版本的时候,那时候是没有泛型的概念的.当时 Java 程序员们写集合类的代码都 ...

  8. JAVA泛型知识(一)

    Java泛型知识(二)<? extends T>和<? super T> Java1.5泛型指南中文版(Java1.5 Generic Tutorial) 目        录 ...

  9. 一个小栗子聊聊JAVA泛型基础

    背景 周五本该是愉快的,可是今天花了一个早上查问题,为什么要花一个早上?我把原因总结为两点: 日志信息严重丢失,茫茫代码毫无头绪. 对泛型的认识不够,导致代码出现了BUG. 第一个原因可以通过以后编码 ...

最新文章

  1. 【摄像头】宽动态范围
  2. 一张图读懂“云栖大会·南京峰会”重磅发布产品
  3. Linux 高可用(HA)集群之keepalived详解
  4. 【死磕Sharding-jdbc】—–最大努力型事务
  5. 五分钟轻松搞定产品需求文档!这可能史上最全PRD文档模板…
  6. QGIS怎样设置简体中文以及新建可编辑的多边形的图层
  7. OpenCASCADE: Code::Blocks构建OCCT
  8. 用信号量锁定:一个例子
  9. Windows 2008 R2阿里云安全基线检查
  10. Android使用webview控件加载本地html,通过Js与后台Java实现数据的传递
  11. ssh 端口_【科普】SSH都不懂,还搞什么网络
  12. 那个悲伤的朋友,去了一趟菜场竟然活过来了
  13. appium自动化测试_Appium自动化测试入门教程No.1—— Appium介绍
  14. 计算机设备故障类型有哪些,计算机硬件故障有哪些
  15. 判断能否被3,5,7整除(信息学奥赛一本通-T1047)
  16. Vb如何设计编程计算机,vb程序设计论文
  17. 如何在标准的机器学习流程上玩出新花样?
  18. 32位MD5加密 可用来微信加密
  19. 鸿蒙曰蜉蝣不知所求,【经典金句408 · 庄子】:浮游,不知所求;猖狂,不知所往;游者鞅掌,以观无妄。...
  20. 企业微信和个人微信区别到底有哪些

热门文章

  1. 铁线蕨算法(Adiantum)为低端智能手机提供磁盘加密服务
  2. class 与 原型链 解析
  3. 批量建立用户和设置密码,批量删除用户脚本
  4. rsync同步服务实验讲解
  5. Coredata — 入门使用
  6. 构建并购重组服务链 蚁合拟推出三大数据平台
  7. javascript客户端检测技术
  8. Paramiko: SSH and SFTP With Python
  9. 虚拟化管理的两大棘手之处
  10. 防止email被抓取的两种方法(js和css)