Java泛型读书笔记 (一)
Java泛型
在Java SE7和之后的版本中,在new一个泛型类实例的时候,可以不传入类型参数,因为Java编译器可以通过赋给的变量类型声明推断出来,如下代码:
ArrayList<String> files = new ArrayList<>();
编译器自动将String传入到ArrayList的泛型类参数中。
泛型类表现为普通类的一个工厂,泛型类通过传入不同的类型参数,可以生产出不同的类来。
泛型类型的边界
可以使用如下代码定义一个泛型T的边界:
<T extends BoundingType>
这里定义了T扩展自BoundingType,这个BoundingType既可以是一个接口,也可以是一个类。
一个类型参数或者一个通配符?可以有多个边界,例如下面的代码:
T extends Comparable & Serializable
不同的边界使用&符号分开,而且这些边界中,只能有一个是类,其他的都要是接口,也就是与Java的继承机制相同。并且如果用一个类作为边界,那么必须写在extends后面的第一个位置上,后面再写接口。
泛型参数的擦除
当定义一个泛型类型时,Java会自动提供一个原始类型,这个原始类型的名字就是不带泛型的类名,并且Java编译器会将类型参数擦除掉,变为普通类型。
擦除的原则是,如果泛型类型 T 没有定义边界,那么就将其替换为Object。如果有边界,就替换为边界。
如下代码是Pair< T> 的定义:
public class Pair<T>
{
private T second;
private T first;
public Pair()
{
first = null;
second = null;
}
public Pair(T first, T second)
{
this.first = first;
this.second =second;
}
public T getFirst()
{
return first;
}
public T getSecond()
{
return second;
}
public void setFirst(T newValue)
{
first = newValue;
}
public void setSecond(T newValue)
{
second = newValue;
}
}
编译器会进行类型擦除,将其变为下面的普通类:
public class Pair
{
private Object second;
private Object first;
public Pair()
{
first = null;
second = null;
}
public Pair(Object first, Object second)
{
this.first = first;
this.second =second;
}
public Object getFirst()
{
return first;
}
public Object getSecond()
{
return second;
}
public void setFirst(Object newValue)
{
first = newValue;
}
public void setSecond(Object newValue)
{
second = newValue;
}
}
对于有边界的泛型类,如果有多个边界,如下面的代码,那么Java编译器会自动擦除到第一个边界:
public class Interval<T extends Comparable & Serializable> implements Serializable
{
private T lower;
private T upper;
...
public Interval(T first, T second)
{
if (first.compareTo(second) <= 0)
{
lower = first;
upper = second;
}
else
{
lower = second;
upper = first;
}
}
}
在进行类型擦除后,上面的代码,将擦除到第一个边界Comparable,实际在java虚拟机中代码是这个样子的:
public class Interval implements Serializable
{
private Comparable lower;
private Comparable upper;
...
public Interval(Comparable first, Comparable second)
{
...
}
}
如果上面的代码将边界的顺序换一下:
<T extends Serializable & Comparable>
那么编译器会擦除到Serializable, 并且编译器会在必要的地方自动加上强制类型转换语句,将Serializable转为Comparable:
public class Interval implements Serializable
{
private Serializable lower;
private Serializable upper;
...
public Interval(Serializable first, Serializable second)
{
if (((Comparable)first).compareTo((Comparable)second) <= 0)
{
lower = first;
upper = second;
}
else
{
lower = second;
upper = first;
}
...
}
}
同样,对于泛型方法也是需要擦除的,如下代码:
public static <T extends Comparable> T min(T[] a)
将被编译器擦除为:
public static Comparable min(Comparable[] a)
注意:
当一个方法的返回类型是泛型时,由于擦除机制,实际返回的是Object或者边界类型,那么编译器会自动加入类型转换语句将擦除的对象转换为正常的对象类型。
如下面的代码:
Pair<Employee> buddies = ...
Employee buddy = buddies.getFirst();
实际上,在类型擦除后,buddies.getFirst()返回的不是Employee类型的实例,而是Obecject类型的,而编译器会自动加入类型装换将Object转换为Employee
总结:
在调用一个泛型方法时,编译器会将一个调用语句分为两步执行
- 调用原始类型Pair.getFirst方法
- 将Object类型转换为Employee类型
:first-child{margin-top:0!important}img.plugin{box-shadow:0 1px 3px rgba(0,0,0,.1);border-radius:3px}iframe{border:0}figure{-webkit-margin-before:0;-webkit-margin-after:0;-webkit-margin-start:0;-webkit-margin-end:0}kbd{border:1px solid #aaa;-moz-border-radius:2px;-webkit-border-radius:2px;border-radius:2px;-moz-box-shadow:1px 2px 2px #ddd;-webkit-box-shadow:1px 2px 2px #ddd;box-shadow:1px 2px 2px #ddd;background-color:#f9f9f9;background-image:-moz-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-o-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:-webkit-linear-gradient(top,#eee,#f9f9f9,#eee);background-image:linear-gradient(top,#eee,#f9f9f9,#eee);padding:1px 3px;font-family:inherit;font-size:.85em}.oembeded .oembed_photo{display:inline-block}img[data-echo]{margin:25px 0;width:100px;height:100px;background:url(../img/ajax.gif) center center no-repeat #fff}.spinner{display:inline-block;width:10px;height:10px;margin-bottom:-.1em;border:2px solid rgba(0,0,0,.5);border-top-color:transparent;border-radius:100%;-webkit-animation:spin 1s infinite linear;animation:spin 1s infinite linear}.spinner:after{content:'';display:block;width:0;height:0;position:absolute;top:-6px;left:0;border:4px solid transparent;border-bottom-color:rgba(0,0,0,.5);-webkit-transform:rotate(45deg);transform:rotate(45deg)}@-webkit-keyframes spin{to{-webkit-transform:rotate(360deg)}}@keyframes spin{to{transform:rotate(360deg)}}p.toc{margin:0!important}p.toc ul{padding-left:10px}p.toc>ul{padding:10px;margin:0 10px;display:inline-block;border:1px solid #ededed;border-radius:5px}p.toc li,p.toc ul{list-style-type:none}p.toc li{width:100%;padding:0;overflow:hidden}p.toc li a::after{content:"."}p.toc li a:before{content:"• "}p.toc h5{text-transform:uppercase}p.toc .title{float:left;padding-right:3px}p.toc .number{margin:0;float:right;padding-left:3px;background:#fff;display:none}input.task-list-item{margin-left:-1.62em}.markdown{font-family:"Hiragino Sans GB","Microsoft YaHei",STHeiti,SimSun,"Lucida Grande","Lucida Sans Unicode","Lucida Sans",'Segoe UI',AppleSDGothicNeo-Medium,'Malgun Gothic',Verdana,Tahoma,sans-serif;padding:20px}.markdown a{text-decoration:none;vertical-align:baseline}.markdown a:hover{text-decoration:underline}.markdown h1{font-size:2.2em;font-weight:700;margin:1.5em 0 1em}.markdown h2{font-size:1.8em;font-weight:700;margin:1.275em 0 .85em}.markdown h3{font-size:1.6em;font-weight:700;margin:1.125em 0 .75em}.markdown h4{font-size:1.4em;font-weight:700;margin:.99em 0 .66em}.markdown h5{font-size:1.2em;font-weight:700;margin:.855em 0 .57em}.markdown h6{font-size:1em;font-weight:700;margin:.75em 0 .5em}.markdown h1+p,.markdown h1:first-child,.markdown h2+p,.markdown h2:first-child,.markdown h3+p,.markdown h3:first-child,.markdown h4+p,.markdown h4:first-child,.markdown h5+p,.markdown h5:first-child,.markdown h6+p,.markdown h6:first-child{margin-top:0}.markdown hr{border:1px solid #ccc}.markdown p{margin:1em 0;word-wrap:break-word}.markdown ol{list-style-type:decimal}.markdown li{display:list-item;line-height:1.4em}.markdown blockquote{margin:1em 20px}.markdown blockquote>:first-child{margin-top:0}.markdown blockquote>:last-child{margin-bottom:0}.markdown blockquote cite:before{content:'\2014 \00A0'}.markdown .code{border-radius:3px;word-wrap:break-word}.markdown pre{border-radius:3px;word-wrap:break-word;border:1px solid #ccc;overflow:auto;padding:.5em}.markdown pre code{border:0;display:block}.markdown pre>code{font-family:Consolas,Inconsolata,Courier,monospace;font-weight:700;white-space:pre;margin:0}.markdown code{border-radius:3px;word-wrap:break-word;border:1px solid #ccc;padding:0 5px;margin:0 2px}.markdown img{max-width:100%}.markdown mark{color:#000;background-color:#fcf8e3}.markdown table{padding:0;border-collapse:collapse;border-spacing:0;margin-bottom:16px}.markdown table tr td,.markdown table tr th{border:1px solid #ccc;margin:0;padding:6px 13px}.markdown table tr th{font-weight:700}.markdown table tr th>:first-child{margin-top:0}.markdown table tr th>:last-child{margin-bottom:0}.markdown table tr td>:first-child{margin-top:0}.markdown table tr td>:last-child{margin-bottom:0}.MathJax_Hover_Frame{border-radius:.25em;-webkit-border-radius:.25em;-moz-border-radius:.25em;-khtml-border-radius:.25em;box-shadow:0 0 15px #83A;-webkit-box-shadow:0 0 15px #83A;-moz-box-shadow:0 0 15px #83A;-khtml-box-shadow:0 0 15px #83A;border:1px solid #A6D!important;display:inline-block;position:absolute}.MathJax_Hover_Arrow{position:absolute;width:15px;height:11px;cursor:pointer}#MathJax_About{position:fixed;left:50%;width:auto;text-align:center;border:3px outset;padding:1em 2em;background-color:#DDD;color:#000;cursor:default;font-family:message-box;font-size:120%;font-style:normal;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;z-index:201;border-radius:15px;-webkit-border-radius:15px;-moz-border-radius:15px;-khtml-border-radius:15px;box-shadow:0 10px 20px gray;-webkit-box-shadow:0 10px 20px gray;-moz-box-shadow:0 10px 20px gray;-khtml-box-shadow:0 10px 20px gray;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}.MathJax_Menu{position:absolute;background-color:#fff;color:#000;width:auto;padding:5px 0;border:1px solid #CCC;margin:0;cursor:default;font:menu;text-align:left;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;z-index:201;border-radius:5px;-webkit-border-radius:5px;-moz-border-radius:5px;-khtml-border-radius:5px;box-shadow:0 10px 20px gray;-webkit-box-shadow:0 10px 20px gray;-moz-box-shadow:0 10px 20px gray;-khtml-box-shadow:0 10px 20px gray;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}.MathJax_MenuItem{padding:1px 2em;background:0 0}.MathJax_MenuArrow{position:absolute;right:.5em;color:#666}.MathJax_MenuActive .MathJax_MenuArrow{color:#fff}.MathJax_MenuArrow.RTL{left:.5em;right:auto}.MathJax_MenuCheck{position:absolute;left:.7em}.MathJax_MenuCheck.RTL{right:.7em;left:auto}.MathJax_MenuRadioCheck{position:absolute;left:.7em}.MathJax_MenuRadioCheck.RTL{right:.7em;left:auto}.MathJax_MenuLabel{padding:1px 2em 3px 1.33em;font-style:italic}.MathJax_MenuRule{border-top:1px solid #DDD;margin:4px 3px}.MathJax_MenuDisabled{color:GrayText}.MathJax_MenuActive{background-color:#606872;color:#fff}.MathJax_Menu_Close{position:absolute;width:31px;height:31px;top:-15px;left:-15px}#MathJax_Zoom{position:absolute;background-color:#F0F0F0;overflow:auto;display:block;z-index:301;padding:.5em;border:1px solid #000;margin:0;font-weight:400;font-style:normal;text-align:left;text-indent:0;text-transform:none;line-height:normal;letter-spacing:normal;word-spacing:normal;word-wrap:normal;white-space:nowrap;float:none;box-shadow:5px 5px 15px #AAA;-webkit-box-shadow:5px 5px 15px #AAA;-moz-box-shadow:5px 5px 15px #AAA;-khtml-box-shadow:5px 5px 15px #AAA;filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=2, OffY=2, Color='gray', Positive='true')}#MathJax_ZoomOverlay{position:absolute;left:0;top:0;z-index:300;display:inline-block;width:100%;height:100%;border:0;padding:0;margin:0;background-color:#fff;opacity:0;filter:alpha(opacity=0)}#MathJax_ZoomFrame{position:relative;display:inline-block;height:0;width:0}#MathJax_ZoomEventTrap{position:absolute;left:0;top:0;z-index:302;display:inline-block;border:0;padding:0;margin:0;background-color:#fff;opacity:0;filter:alpha(opacity=0)}.MathJax_Preview{color:#888}#MathJax_Message{position:fixed;left:1px;bottom:2px;background-color:#E6E6E6;border:1px solid #959595;margin:0;padding:2px 8px;z-index:102;color:#000;font-size:80%;width:auto;white-space:nowrap}#MathJax_MSIE_Frame{position:absolute;top:0;left:0;width:0;z-index:101;border:0;margin:0;padding:0}.MathJax_Error{color:#C00;font-style:italic}footer{position:fixed;font-size:.8em;text-align:right;bottom:0;margin-left:-25px;height:20px;width:100%}
-->
Java泛型读书笔记 (一)的更多相关文章
- Java泛型读书笔记 (二)
关于Java泛型擦除后,继承一个泛型类带来的问题 有如下泛型类Pair: public class Pair<T> { private T second; private T first; ...
- Java泛型读书笔记 (三)
泛型对于老代码的支持 Java的泛型设计成类型擦除的目的,很大一部分是为了兼容老老代码.如下的一段代码: void setLabelTable(Dictionary table) table的类型是非 ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- Java并发读书笔记:线程安全与互斥同步
目录 导致线程不安全的原因 什么是线程安全 不可变 绝对线程安全 相对线程安全 线程兼容 线程对立 互斥同步实现线程安全 synchronized内置锁 锁即对象 是否要释放锁 实现原理 啥是重进入? ...
- 单元测试之道Java版——读书笔记
单元测试知道Java版读书笔记 首先我们必须要知道我们所写的代码,它的功能是什么,如果我们不了解代码的行为,那么也就无从测试. 我们测试的目的,是为了我们整个程序架构的稳定,代码其实就是欧文要实现功能 ...
- Java泛型学习笔记 - (七)浅析泛型中通配符的使用
一.基本概念:在学习Java泛型的过程中, 通配符是较难理解的一部分. 主要有以下三类:1. 无边界的通配符(Unbounded Wildcards), 就是<?>, 比如List< ...
- Java泛型学习笔记--Java泛型和C#泛型比较学习(一)
总结Java的泛型前,先简单的介绍下C#的泛型,通过对比,比较学习Java泛型的目的和设计意图.C#泛型是C#语言2.0和通用语言运行时(CLR)同时支持的一个特性(这一点是导致C#泛型和Java泛型 ...
- 《Effective Java》读书笔记 - 5.泛型
Chapter 5 Generics Item 23: Don't use raw types in new code 虽然你可以把一个List<String>传给一个List类型(raw ...
随机推荐
- Yii错误404页面
'errorHandler'=>array( // use 'site/error' action to display errors 'errorAction'=>YII_DEBUG ? ...
- 最终还是选择了markdownpad2
markdownpad2使用 最终 哈哈,最后还是选择了markdownpad2,经过探索才知道这个玩意多么好用. 点击,下载. 碰到的问题 1.win10出现HTML无法渲染得对话框 结果是,官网有 ...
- Activiti:MalformedByteSequenceException: 3 字节的 UTF-8 序列的字节 3 无效。
在win下开发,有时编译或运行项目会报3字节的UTF-8序列的字节3无效. 解决该问题的办法 1.将xml头文件改为GBK编码方式 ,我这里不OK <?xml version="1.0 ...
- 【转】 Pro Android学习笔记(八七):了解Handler(1):组件和线程
目录(?)[-] 主线程消息队列和线程池 查看线程信息 文章转载只能用于非商业性质,且不能带有虚拟货币.积分.注册等附加条件.转载须注明出处:http://blog.csdn.net/flowingf ...
- java流的操作步骤、、
在java中使用IO操作必须按照以下的步骤完成: 使用File找到一个文件 使用字节流或字符流的子类为OutputStream.InputStream.Writer.Reader进行实例化操 作 ...
- Angular学习笔记-问题列表(2016.4.7)
1.控制器中注入服务时,出问题,当前pageInit这个页面无法加载,页面无报错信息. var homepage = angular.module('homepage'); homepage.cont ...
- MFC鼠标键盘消息处理
void CMainWindow::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags ){ )&&(GetKeyState(VK_LBUT ...
- Solaris ssh配置主机间信任关系
假设需要配置从主机com00biiitf001登录主机ols00biiitf001时不需要密码,则采用以下步骤配置: com00biiitf001上产生公用/私有密钥对 $ ssh-keygen -t ...
- ABP工作单元
简介 Unit of work:维护受业务事务影响的对象列表,并协调变化的写入和并发问题的解决.即管理对象的CRUD操作,以及相应的事务与并发问题等.Unit of Work是用来解决领域模型存储和变 ...
- Shell编程进阶 1.6 if判断的几种用法
针对文件和目录的逻辑判断 touch .txt .txt ]; then echo ok;fi -f 判断1.txt是否是文件且是否存在,成立输出ok if [-d /tmp/ ]; then ech ...