Java泛型读书笔记 (三)
泛型对于老代码的支持
Java的泛型设计成类型擦除的目的,很大一部分是为了兼容老老代码。如下的一段代码:
void setLabelTable(Dictionary table)
table的类型是非泛型的Dictionary,但是我们可以传入泛型的Dictionary:
Dictionary<Integer, Component> labelTable = new Hashtable<>();
labelTable.put(0, new JLabel(new ImageIcon("nine.gif")));
labelTable.put(20, new JLabel(new ImageIcon("ten.gif")));
...
slider.setLabelTable(labelTable); // WARNING
注意,当向setLabelTable传入一个泛型的Dic,编译器会产生一个警告。
还有一种相反的情况,一个方法的返回类型是原始类型,但是可以分配给一个泛型类型持有:
Dictionary<Integer, Components> labelTable = slider.getLabelTable(); // WARNING
这种情况也会产生一个警告信息。
可以是用java注解来使这些警告消失掉:
@SuppressWarnings("unchecked")
Dictionary<Integer, Components> labelTable = slider.getLabelTable(); // No warning
或者注解在整个方法上面,使得方法内的所有警告消失:
@SuppressWarnings("unchecked")
public void configureSlider() { . . . }
泛型的使用限制
泛型的很多限制都是由于类型擦除机制带来的
泛型的类型参数不能是原始类型
Type Parameters Cannot Be Instantiated with Primitive Types
不能用Pair<double>,而只能使用Pair<Double>
运行时的类型查询与判断只能作用于非泛型类型,不支持泛型类的类型查询
Runtime Type Inquiry Only Works with Raw Types
由于Java虚拟机运行的代码都是没有泛型的,所以只能对非泛型类型进行类型查询与判断,如下代码是错误的:
if (a instanceof Pair<String>) // ERROR
if (a instanceof Pair<T>) // ERROR
只能对a instanceof Pair,不能判断泛型类。
下面这种情况会查询一个编译时的警告
Pair<String> p = (Pair<String>) a; // WARNING--can only test that a is a Pair
同样的,进行下面的判断,也只是对擦除后的类型进行的,与使用的什么类型参数无关:
Pair<String> stringPair = . . .;
Pair<Employee> employeePair = . . .;
if (stringPair.getClass() == employeePair.getClass()) // they are equal
上面的比较返回的是true,因为他们都属于擦除后的类型Pair.class
不能创建泛型类的数组
You Cannot Create Arrays of Parameterized Types
下面这种代码是错误的:
Pair<String>[] table = new Pair<String>[10]; // ERROR
在类型擦除后,table的类型实际上是Pair[],可以将其转换为Object[]类型:
Object[] objarray = table;
由于数组是可以记住它内部元素的类型的,并且当你试图存储一个类型不匹配的元素时,会抛出ArrayStoreException异常。
那么像下面的代码:
objarray[0] = new Pair<Employee>();
首先,进行类型擦除,那么就变成了objarray[0] = new Pair();
但是objarray记住的内部元素类型应该是Pair, 与Pair不符,那么就会抛出异常。
由于这种情况,Java不允许new一个泛型类型的数组。
如果需要存储泛型类对象的集合,直接使用ArrayList即可,既安全又高效。
ArrayList<Pair<String>>
可变参数使用泛型类型
像下面这种泛型类型作为可变参数:
public static <T> void addAll(Collection<T> coll, T... ts)
{
for (t : ts) coll.add(t);
}
由于可变参数实际上是语法糖,就是一个数组,那么ts就是一个T[]数组,当我们使用这个addAll方法,如下:
Collection<Pair<String>> table = ...;
Pair<String> pair1 = ...;
Pair<String> pair2 = ...;
addAll(table, pair1, pair2);
Java会将形参ts转换为Pair泛型类型数组:
Pair<String>[]
根据上一个限制,Java是不允许创建泛型类型的数组的。但是,在这里Java允许创建这种泛型类型数组。
这样传入泛型对象时,Java会报出警告信息,可以使用注解放在包含调用addAll方法的方法来去掉这种警告:
@SuppressWarnings("unchecked")
在Java7以后,可以使用新的注解@SafeVarargs来注解addAll方法本身,来去掉这种警告:
@SafeVarargs
public static <T> void addAll(Collection<T> coll, T... ts)
不能初始化泛型类类型参数
不能像如下代码使用来直接new一个类型参数:
new T(...), new T[...], or T.class.
如下在Pair< T >中直接new一个类型参数是非法的:
public Pair() { first = new T(); second = new T(); } // ERROR
因为类型擦除,会将T擦除为Object,那么上面的代码直接就是new Object(), 显然不是我们想要的。
workaround的方法是使用反射机制来new一个泛型类型的对象,使用时,需要多传入一个Class< T > 对象,如下:
public static <T> Pair<T> makePair(Class<T> cl)
{
try
{
return new Pair<>(cl.newInstance(), cl.newInstance())
}
catch (Exception ex)
{
return null;
}
}
上面的方法需要使用方传入一个泛型类型T的Class对象,然后使用Class的newInstance方法产生泛型类型的实例。
注意,Class自身就是泛型的,比如,String.class就是一个Class< String >的实例。
同样也不允许直接new一个泛型类型数组,如下代码:
// ERROR
public static <T extends Comparable> T[] minmax(T[] a)
{
T[] mm = new T[2];
. . .
}
上面的代码,擦除到边界后变为了Comparable[] mm = new Comparable[2]; 这也不是我们想要的,如果你只想将泛型类数组当成一个内部使用的字段,那么可以想下面的ArrayList< E> 一样直接内部使用Object[] 即可:
public class ArrayList<E>
{
private Object[] elements;
...
@SuppressWarnings("unchecked")
public E get(int n)
{
return (E)elements[n];
}
public void set(int n, E e)
{
// no cast needed
elements[n] = e;
}
}
当然,如果需要在一个方法中返回泛型数组的话,下面的代码是错误的:
public static <T extends Comparable> T[] minmax(T... a)
{
Object[] mm = new Object[2];
...
return (T[]) mm; // compiles with warning
}
因为编译器会擦除到Comparable,返回的数组就不是你想要的泛型类型数组了,解决方法如下:
public static <T extends Comparable> T[] minmax(T... a)
{
T[] mm = (T[]) Array.newInstance(a.getClass().getComponentType(), 2);
...
}
使用Array的newIntance方法来生成数组。
类的静态字段不能使用泛型类
下面的静态字段不能使泛型类:
public class Singleton<T>
{
private static T singleInstance; // ERROR
public static T getSingleInstance() // ERROR
{
if (singleInstance == null)
{
construct new instance of T
return singleInstance;
}
}
}
因为类型擦除,singleInstance不管传入什么,都是一个Object类型,所以没有意义。
不能抛出泛型类异常,也不能捕获泛型类异常的实例
下面的代码,直接扩展Exception是不允许的:
public class Problem<T> extends Exception { /* . . . */ } // ERROR-- can't extend Throwable
下面的代码,也不能catch一个泛型类型的异常:
public static <T extends Throwable> void doWork(Class<T> t)
{
try
{
do work
}
catch (T e) // ERROR--can't catch type variable
{
Logger.global.info(...)
}
}
但是泛型类型参数作为方法名后的throws T是允许的,像下面的代码:
public static <T extends Throwable> void doWork(T t) throws T // OK
{
try
{
do work
}
catch (Throwable realCause)
{
t.initCause(realCause);
throw t;
}
}
注意泛型参数被擦除后带来的冲突
如下代码:
public class Pair<T>
{
public boolean equals(T value)
{
return first.equals(value) && second.equals(value);
}
...
}
当我们定义了一个Pair< String>泛型类,如果没有擦除机制,那么Pair< String>类里面会有两个如下的equals方法,一个定义在此类中,另一个定义在隐式继承类Object中:
boolean equals(String) // defined in Pair<T>
boolean equals(Object) // inherited from Object
但是,在擦除掉Pair< String>中的String后,实际上下面这个equals方法:
boolean equals(T)
擦除后变为了下面这样:
boolean equals(Object)
那么这个equals方法就覆盖掉了Object类中的equals方法,也就发生了冲突。解决方法很简单,就是重命名Pair< T>中的equals方法。
不允许一个类继承自两个只是泛型类参数不同的类
像下面的GregorianCalendar类,间接继承自Comparable和Comparable两个只是泛型类参数不同的同一个接口是不允许的:
class Calendar implements Comparable<Calendar> { . . . }
class GregorianCalendar extends Calendar implements Comparable<GregorianCalendar>
{ . . . } // ERROR
泛型类型的继承规则
如果Employee是父类,Manager继承自Employee,那么这两个类作为同一个泛型类的类型参数时,这两个泛型类没有任何关系
注意泛型类与Java数组之间的一个重要的区别,可以将一个Manager[]数组赋给一个类型为Employee[]数组的变量:
Manager[] managerBuddies = {ceo, cfo};
Employee[] employeeBuddies = managerBuddies; //OK
然而,数组带有特别的保护,如果试图将一个低级别的Employee存储到employeeBuddies[0], 虚拟机将会抛出ArrayStoreException异常。
你总是可以将一个泛型类型转换为它的原始类型,例如,Pair< Employee>是原始类型
Pair的一个子类,这种转换能力是用来兼容Java老代码的。
最后,泛型类可以继承或者实现其他泛型类,在这一点上,它与普通类没有区别。例如,ArrayList< T>实现了接口List< T>,那么ArrayList< Manager>就可以转换为List< Manager>,但是ArrayList< Manager>与ArrayList< Employee>和List< 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泛型 在Java SE7和之后的版本中,在new一个泛型类实例的时候,可以不传入类型参数,因为Java编译器可以通过赋给的变量类型声明推断出来,如下代码: ArrayList<Strin ...
- Java泛型读书笔记 (二)
关于Java泛型擦除后,继承一个泛型类带来的问题 有如下泛型类Pair: public class Pair<T> { private T second; private T first; ...
- Java泛型学习笔记 - (三)泛型方法
泛型方法其实和泛型类差不多, 就是把泛型定义在方法上, 格式大概就是: public <类型参数> 返回类型 方法名(泛型类型 变量名) {...}泛型方法又分为动态方法和静态方法,:1. ...
- 《Effective Java》读书笔记三(类和接口)
No13 使类和成员的可访问性最小化 要区别设计良好的模块与设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节.模块之间只通过它们的API进行通信,一个 ...
- Java Script 读书笔记 (三) 函数
1. 函数作用域 在函数内部定义的变量,外部无法读取,称为"局部变量"(local variable). 变量v在函数内部定义,所以是一个局部变量,函数之外就无法读取. 函数内部定 ...
- java effective 读书笔记
java effective 读书笔记 []创建和销毁对象 静态工厂方法 就是“封装了底层 暴露出一个访问接口 ” 门面模式 多参数时 用构建器,就是用个内部类 再让内部类提供构造好的对象 枚举 si ...
- Java IO学习笔记三
Java IO学习笔记三 在整个IO包中,实际上就是分为字节流和字符流,但是除了这两个流之外,还存在了一组字节流-字符流的转换类. OutputStreamWriter:是Writer的子类,将输出的 ...
- 深入理解Java虚拟机 -- 读书笔记(1):JVM运行时数据区域
深入理解Java虚拟机 -- 读书笔记:JVM运行时数据区域 本文转载:http://blog.csdn.net/jubincn/article/details/8607790 本系列为<深入理 ...
- 【转载】MDX Step by Step 读书笔记(三) - Understanding Tuples (理解元组)
1. 在 Analysis Service 分析服务中,Cube (多维数据集) 是以一个多维数据空间来呈现的.在Cube 中,每一个纬度的属性层次结构都形成了一个轴.沿着这个轴,在属性层次结构上的每 ...
随机推荐
- shell 实现闰年的判断
#!/bin/shecho "please input the year"read year let "n1=$year % 4"let "n2=$y ...
- JSONP原理及实现跨域方式
今天做页面时,后台给了个接口:https://a.a.com/a/a.json,我页面的上线地址是:http://b.b.com.显而易见,因为浏览器同源策略的限制,通过ajax无法无法取得json的 ...
- bzoj 1951 [Sdoi2010]古代猪文 ——数学综合
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1951 数学综合题. 费马小定理得指数可以%999911658,又发现这个数可以质因数分解.所 ...
- java编程思想第九章接口
9.1抽象类和抽象方法 为什么要有抽象类? 是希望通过通用接口操作一系列类. 那么抽象类的形式是什么样的呢? 声明类的使用使用abstract关键字,且在该类中应该具有抽象方法. 注:抽象方法被关键字 ...
- dockerfile mysql
FROM centos6.6-mysql5.5:0.0.4 MAINTAINER syberos:wangmo RUN mv /etc/my.cnf /etc/my.cnf.bak ADD my.cn ...
- centos7 安装 mysql-python时 报错 EnvironmentError: mysql_config not found
pip install mysql-python 然后报错 EnvironmentError: mysql_config not found 网上搜解决方法,需要安装 mysql-devel 然后 ...
- 用PowerShell在China Azure创建ARM虚拟机
Azure目前有两种工作模式:ASM和ARM. 在国内的Azure,我们都是使用ASM的模式.但这种模式有很多限制,比如每个VM必须有一个公网地址,部署不能批量部署等等.ARM对Azure的整体架构做 ...
- JAVA 正则表达式 Regex
//正则表达式,去掉空格.换行.制表位 public static void replaceBlank(){ Pattern p = Pattern.compile("\\s*|\t|\r| ...
- EMIPLIB简介
EMIPLIB(http://research.edm.uhasselt.be/emiplib)的全称是'EDM Media over IP libray' .EDM是Hasselt Universi ...
- 杂项:MIME(多用途互联网邮件扩展类型)百科
ylbtech-杂项:MIME(多用途互联网邮件扩展类型)百科 MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定某种扩展名的文件用 ...