Java Generics
2012-11-26 09:20 congdepeng 阅读(184) 评论(0) 收藏 举报Generics
generic
generic /dʒəˈner.ɪk/
adjective 形容词
1 FORMAL shared by, typical of or relating to a whole group of similar things, rather than to any particular thing:
1 FORMAL shared by, typical of or relating to a whole group of similar things, rather than to any particular thing:
共享,共性
The new range of engines all had a generic problem with their fan blades.
2 MAINLY US describes a product that is not marked with the name of the company that produced it:
The new range of engines all had a generic problem with their fan blades.
2 MAINLY US describes a product that is not marked with the name of the company that produced it:
一般的
a generic drug
a generic drug
generic
adj 种属的;普遍的=general
【记】源于:gene基因genus(n 生物学种类);genre(n 文学类型;流派)
【区】genetic(adj 遗传的;起源的)"
【记】源于:gene基因genus(n 生物学种类);genre(n 文学类型;流派)
【区】genetic(adj 遗传的;起源的)"
反义词:
Specific
因为Object是所有对象的超类,所以它可以用在处理任意类型的时候作为占位。
然而,如果当该用String作为参数的时候,你使用了Object来占位,然后你可以将Object转为String来使用, 那么只有你才知道这个潜规则,Java程序是无法预知这个规则的,那么Java程序就无法帮你做必要的验证,当你不小心使用Integer作为参数的时候而想转换成String的时候就会出错,本质的原因是“信息丢失”了,你无法将这个潜规则反应到程序里面。
Generic的出现就是为了弥补这个缺陷!
type variable 类型变量
<E> -- 表示Element类型,即是对象的一个元素。
<K> -- 表示Key类型
<V> -- 表示Value类型
<T> -- 表示通用Generic类型
(这只是惯例而已,你可以任意定义类型变量名)
无泛型的代码如下:
|
有泛型的代码如下:
你可以认为是没有泛型的代码少了点信息,也可以认为有泛型的代码多了点什么。 既然泛型的存在有一定的作用,那么势必需要多一点信息熵来给起作用的地方去参考。 换个角度来说,也是“数据”和“代码”的一次完美转换。本来我们需要重写任意多的代码,这条路走不通,因为违反了“有穷性”,我们无法完全定义出所有可能性的类型,即代码这条路走不通,于是我们改变了数据结构,在数据结构里面加了一个类型变量,这个变量来指代所有的可能性,以不变应万变。 |
1. 定义
- 泛型类不会因为类型参数不同而存在多份
- 泛型信息在编译后就被擦除,不存在于class文件中
- 泛型是给编译器提供信息而不是运行时
每一个对泛型类的调用都称为一次 parameterized invocation,即使同一个类的参数化的调用而产生的不同对象,但是本质上是共享同一份代码,是同一个类。
因此,对于类方法(Static)和类(Static)字段,都不可以使用泛型参数。
1.2. 类型参数的界限
<E>作为一般形式,并没有限制E的类型,也就是说E可以接受任意类型,但是现实需求往往是需要现在E在一定范围内
<E extends XXXClass>1.3 子类型subtyping和通配符wildcards
wildcard '?'
List<? extends XXX> liststatic double sum(List<Number> list) {
double sum = 0.0;
for (Number n : list)
sum += n.doubleValue();
return sum;
}
List<Integer> l = new ArrayList<Integer>();
l.add(1);
l.add(4);
l.add(9);
double sum = sum(l); // INVALID: won't compile11.5 背后实现原理: 编译时擦除
erasure:因为编译器基本上会将class文件里的所有的泛型类型信息擦除。
- 首先,如果是<E>就替换为Object
- 如果是< E extends ?>, 就替换为最近的那个?
- 如果使用到绑定的非Object方法,就做一个cast
类型擦除影响到如下2个关键点:
- 包含泛型类型的运行时操作
- 方法的重载(同类)和重写{继承}
擦除对运行时的影响如下:
- 无法 new T(), new T[n]
- =============================== 看不懂
对重载和重写的影响
类型擦除后就是如下代码: |
|
泛型:
本质上参数化类型,主要是针对集合,因为如果是非集合,那么类型肯定已经确定了!!!
泛型可以用在类,接口和方法的创建中。
下面举一个用在泛型类中的例子,因为类生产的对象可以看出是一个字典,而字典就是一个集合!
package com.iu.www.generics;
//泛型的写法,非常的通用,不需要类型转换
public class Gen<T> {
private T ob;
public Gen(T ob){
this.ob = ob;
}
public T getOb() {
return ob;
}
public void setOb(T ob) {
this.ob = ob;
}
public void showType(){
System.out.println("the param is : "+ob.getClass().getName());
}
public static void main(String[] args) {
Gen<String> hello = new Gen<String>("Hello");
hello.showType();
}
// 一般的写法, 因为Object没有泛化,所以不清楚Object是什么,所以有强制类型转换的过程,而且这个过程编译器没办法帮助检查,可能会有运行时错误
public class Gen2 {
private Object ob; //定义一个通用类型成员
public Gen2(Object ob) {
this.ob = ob;
}
public Object getOb() {
return ob;
}
public void setOb(Object ob) {
this.ob = ob;
}
public void showTyep() {
System.out.println("T的实际类型是: " + ob.getClass().getName());
}
}
////////////// 最搓的写法, 每个类型都要重复写一遍,重复的模板代码
class GenString {
private String ob;
public GenString(String ob){
this.ob = ob;
}
public String getOb() {
return ob;
}
public void setOb(String ob) {
this.ob = ob;
}
public void showType(){
System.out.println("the param is : "+ob.getClass().getName());
}
}
class GenInteger {
private Integer ob;
public GenInteger(int ob){
this.ob = ob;
}
public Integer getOb() {
return ob;
}
public void setOb(int ob) {
this.ob = ob;
}
public void showType(){
System.out.println("the param is : "+ob.getClass().getName());
}
}
} 其中泛型的参数类型一般有如下几种,但是这只是一个建议而已,你可以改成任何你想要的名字。 E for an element type,
K for a key type,
V for a value type,
T for a general type,
and so forth. 注意如下代码,泛型定义的类型参数不一定是给构造器使用,它可以用在类的任何方法上。 package com.iu.www.generics;
public class Map2<K,V> {
public V get(K key) {
return null;
}
public V put(K key, V value) {
return null;
}
public static void main(String[] args) {
Map2<String, Integer> stringIntegerMap2 = new Map2<String, Integer>();
stringIntegerMap2.put("",1);
Integer integer = stringIntegerMap2.get("");
}
}
浙公网安备 33010602011771号