java 5以后,java引入了“参数化类型”的概念,允许程序在创建集合时指定集合元素的类型

java 7之前,如果使用带泛型的接口、类定义变量,那么调用构造器创建对象时构造器的后面也必须带泛型

比如

//java 7之前

List list = new ArrayList();//后面的是必须带上的

//java 7之后,"菱形"语法

List list = new ArrayList<>();

注:java 9允许在使用匿名内部类时使用菱形语法

概念定义:允许在定义类、接口、方法时使用类型形参,这个类型形参将在声明变量、创建对象、调用方式动态地指定

我们来看一下定义泛型接口、类

/**

* 定义泛型接口,实质:允许在定义接口、类时什么类型形参,

* 类型形参在整个接口、类体内可当成类型使用,几乎所有可

* 使用普通类型的地方都可以使用这种类型形参

*/

public interface List {

void add(T x);

}

/**

* 定义

*

*

*/

@Data

public class Clazz {

private T a;

public Clazz(T a){

this.a = a;

}

}

//使用Clazz

pulic void method(){

Clazz clazz = new Clazz<>("");

}

从泛型类派生子类

当创建了带泛型声明的接口、父类之后,可以为该接口创建实现类,或从该父类派生子类,需要指出的是,当使用这些接口、父类时不能再包含泛型形参

//定义类Son类继承Parent类

public class Son extends Parenet{

}

//使用Parent类时为T形参传入String类型

public class Son extends Parent{

}

//使用Parent类时,没有为T形参传入实际的类型参数

public class Son extends Parent{

}

像这种使用Parent类时省略泛型的形式被称为原始类型(raw type)

如果从Parent类派生子类,则在Parent类中所有使用T类型的地方都将被替换成String类型

并不存在泛型类

List与List 创建出来的是同样class文件,它们在运行时总有同样的类,故在静态方法、静态初始化块或者静态变量的生命和初始化中不允许使用泛型形参

public class R{

//错误,不能在静态变量声明中使用泛型形参

static T info;

//错误,不能再静态方法声明中使用泛型形参

public void foo(T p){

}

}

类型通配符

定义:为了表示各种泛型List的父类,可以使用类型通配符,类型通配符是一个问号(?),将一个问号作为类型实参传给List集合,写作:List>(意思是元素类型未知的List)。这个问号(?)被称为通配符,它的元素类型可以匹配任何类型

类型通配符的上限

定义:当直接使用List>·这种形式时,即表明这个List集合可以是任何泛型List的父类。但还有一种特殊的情形,程序不希望这个List>`是任何泛型List的父类,只希望它代表某一类泛型List的父类

//定义上限为Parent类,表示泛型形参必须是Parent子类

List extends Parent>

协变:对于更广泛的泛型类来说,指定通配符上限就是为了支持类型型变。比如Foo是Bar的子类,这样A就相当于A extends Bar>的子类,可以将A赋值给A extends Bar>类型的变量,这种型变方式被称为协变

类型通配符的下限

定义:通配符的下限用 super类型>的方式来指定,通配符下限的作用与通配符上限的作用恰好相反

//定义下限为Parent类

List super Parent>

逆变:比如Foo是Bar的子类,当程序需要一个A super Foo>变量时,程序可以将A、A赋值给A super Foo>类型的变量,这种型变方式被称为逆变

对于逆变的泛型而言,它只能调用泛型类型作为参数的方法;而不能调用泛型类型作为返回值类型的方法。口诀是:逆变只进不出

泛型方法

定义:所谓泛型方法,就是在声明方法时定义一个或多个泛型形参,与类、接口中使用泛型参数不同的是,方法中的泛型参数无须显式传入实际类型参数修饰符返回值类型 方法名(形参列表){

//TODO

}

泛型方法和类型通配符的区别

使用通配符比使用泛型方法(在方法签名中显式声明泛型形参)更加清晰和准确

类型通配符既可以在方法签名中定义形参的类型,也可以用于定义变量的类型;但泛型方法中的泛型形参必须在对应方法中显式声明

大多数时候都可以使用泛型方法来代替类型通配符//使用类型通配符

public interface Collection{

void add(Collection> p);

void delete(Collection extends E> p)

}

//使用泛型方法

public interface Collection{

void add(Collection p);

void delete(Collection p)

}

也可以同时使用泛型方法和通配符public class Collections{

public static void copy(List dest,List extends T> src){}

}

“菱形”语法与泛型构造器

“菱形”语法前面已经提到,不再赘述,说一下啥是泛型构造器,其实就是java允许构造器签名中声明泛型形参class Foo{

public Foo(T t){

}

}

public void method(){

//泛型构造器中T类型为String

new Foo("");

//也可以这么定义,显示指定T类型为String

new Foo("");

//泛型构造器中T类型为Integer

new Foo(10);

}

泛型方法与方法重载

因为泛型既允许设定通配符的上限,也允许设定通配符的下限,从而允许在一个类里包含以下两种方法的定义 void copy(Collection des,Collection extends T> src){};

T copy(Collection super T> des,Collection src){};

重载的情况public void method(List list){}

public void method(List list){}

上述这段代码是不能被编译的,因为参数List和List编译之后都被擦除了, 变成了同一种的裸类型List,类型擦除导致这两个方法的特征签名变得一模一样(下面会提到类型擦除)

类型推断

java 8改进了泛型方法的类型推断能力,类型推断主要有如下两方面

1)可通过调用方法的上下文来推断泛型的目标类型

2)可在方法调用链中,将推断得到的泛型传递到最后一个方法

泛型擦除和转换

擦除:当把一个具有泛型信息的对象赋给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都将被扔掉;Java代码编译成Class文件, 然后再用字节码反编译工具进行反编译后, 将会发现泛型都不见了, 程序又变回了Java泛型出现之前的写法, 泛型类型都变回了裸类型(List 对应的裸类型就是List)

比如:List 类型会被转换成List,则该List对集合元素的类型检查变成了泛型参数的上限(Object),那么在使用,比如插入的时候,又会出现从Object到String的强制转型代码

擦除法所谓的擦除, 仅仅是对方法的Code属性中的字节码进行擦除, 实际上元数据中还是保留了泛型信息, 这也是我们在编码时能通过反射手段取得参数化类型的根本依据

java不支持原生类型的泛型,即是不支持 int/long等,List这种是不支持的,那么一旦把泛型信息擦除后,遇到原生类型时把装箱、 拆箱也自动做了,这也成为Java泛型慢的重要原因

泛型与数组

数组元素的类型不能包含泛型变量或泛型形参,除非是无上限的类型通配符,但可以声明元素类型包含泛型变量或泛型形参的数组。也就是说,只能声明List[]形式的数组,但不能创建ArrayList[10]这样的数组对象

java模型给泛型_【一天一个基础系列】- java之泛型篇相关推荐

  1. java编程最新图书_清华大学出版社-图书详情-《Java程序设计》

    前言 Java是一种完全面向对象的程序设计语言,具有卓越的通用性.高效性.平台移植性和安全性,得到广泛的应用.在全球云计算和移动互联网产业高速发展的环境下,Java具备显著的优势和广阔前景.本书以Ja ...

  2. java自动推断类型_推断:Facebook的新Java静态分析工具

    java自动推断类型 如何使用Facebook的Infer改善Java开发工作流程? 如果您与技术话题保持同步(如果您正在阅读此博客,我想您会这样做),那么您可能听说过Facebook 刚刚向公众发布 ...

  3. java.policy无法修改_如何配置Policy文件进行Java安全策略的设置

    中国人最喜欢访问的网站 只要注册ofo就送你10块钱,还等什么,快来注册吧 Java语言具有完善的安全框架,从编程语言.编译器.解释程序到Java虚拟机,都能确保Java系统不被恶意的代码或敌对的编译 ...

  4. java channel源码_彤哥说netty系列之Java NIO核心组件之Channel

    你好,我是彤哥,本篇是netty系列的第五篇. 欢迎来我的工从号彤哥读源码系统地学习源码&架构的知识. 简介 上一章我们一起学习了如何使用Java原生NIO实现群聊系统,这章我们一起来看看Ja ...

  5. 中秋节图案 用java代码打出来_这个中秋,我用 Java 画了一个月饼!

    栈长代表微信公众号 "Java技术栈" 祝所有粉丝中秋佳节快乐! 为了用一种特殊的方式表达我的心意,去年中秋节,我写了这篇文章: 没错,去年一天,我学了 20 种编程语言,刺激.. ...

  6. java生成pdf图表_开发员指南:使用Java图表转换为PDF/JPG等图像

    Aspose.Cells for JavaExcel电子表格处理API,它允许Java开发人员在自己的Java应用程序中嵌入可读取.写入和操作Excel电子表格的能力,而无需依赖Microsoft E ...

  7. java语言程序设计你_清华大学出版社-图书详情-《Java语言程序设计》

    前言 Java语言是一种典型的面向对象的.跨平台的.支持分布式和多线程的优秀编程语言,具有极强的扩展性.自其诞生以来,迅速被业界认可并广泛应用于Web应用程序的开发中.在此形势下,国内高校在计算机及相 ...

  8. mac上java文件如何编译_如何在Mac上用Java编译和运行程序?

    小编典典 在Mac OSX或任何主要操作系统上编译和运行Java应用程序非常容易.Apple随OSX一起提供了一个功能齐全的Java运行时和开发环境,因此您要做的就是编写Java程序并使用内置工具来编 ...

  9. java 解析日期格式_日期/时间格式/解析,Java 8样式

    java 解析日期格式 自Java 几乎 开始以来,Java开发人员就通过java.util.Date类(自JDK 1.0起)和java.util.Calendar类(自JDK 1.1起 )来处理日期 ...

最新文章

  1. Android NDK开发之旅29 云服务器Ubuntu下搭建NDK环境,并编译FFmpeg
  2. 技术面试的时候应该了解公司点什么
  3. 最新:全球大型数据中心总数增至597个,是2015年数据中心数量的两倍
  4. mysql5.7.11解压版_Mysql5.7.11在windows10上的安装与配置(解压版)_MySQL
  5. [转]利用ASP.NET 2.0创建自定义Web控件(1)
  6. pycharm创建python虚拟环境好处_pycharm虚拟环境的搭建
  7. 【yolo】ubuntu18.04 yolo打开摄像头实时检测框目标 转化pth文件为onnx
  8. openshift安装部署_OpenShift 4 HOL (1) - 多种方法部署容器化应用
  9. VDI序曲二十七 IE7,IE8,IE9应用程序虚拟化
  10. 网页表单form中提交的两种方式
  11. python计算二维平面的曲线的曲率
  12. 天合光能环卫机器人_无人驾驶已在南京多个领域落地!无人环卫,离全面落地还有多久...
  13. Eclipse中直接执行sql语句(图文说明)
  14. NET 技术FAQ(六)-----属性
  15. 关于layui的日期和时间组件LayData时间选择器使用时一闪而过
  16. CCNA学习指南 第八章 下载
  17. 史上最全最详细的PS3模拟器安装及设置教程
  18. 基于STM32的无损压缩算法miniLZO移植,压缩率很高,20KB随机数压缩到638字节,耗时275us
  19. 【零基础跑项目】20代码教你基于opencv的人脸检测
  20. 监督学习之分类学习:支持向量机

热门文章

  1. c++构造函数详解(转)
  2. 为什么用Spring来管理Hibernate?
  3. Oracle RAC更改VIP IP地址_2节点的实验
  4. JDBC批量Insert深度优化(有事务)
  5. linux mesg 命令详解
  6. ER图转换成关系模式集的规则
  7. java老鸟123怎么样_java入门123——一个老鸟的java学习心得.doc
  8. python 登陆微博 被删除 token_爬取微博信息,使用了cookie仍然无法登录微博
  9. asp.net 获取全部在线用户_Qamp;A | 在线考试问卷答疑
  10. 用2468这四个数字c语言,C语言作业及参考答案.doc