java 泛型(Generics)变量类型的参数化。
工作中经常会用的到,今天自己也总结下对泛型的认识,来看看泛型到底有哪些fun。
1、普通泛型
class Point< T >{ private T var ; public T getVar(){ return var ; } public void setVar(T var){ this.var = var ; } }; public class GenericsDemo{ public static void main(String args[]){ Point< String> p = new Point< String>() ; p.setVar("test") ; System.out.println(p.getVar().length()) ; } };
2、泛型接口
interface Info< T >{ public T getVar() ; } class InfoImpl< T> implements Info< T >{ // 这里的 T 可以是具体的类型 private T var ; public InfoImpl(T var){ this.setVar(var) ; } public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } }; public class GenericsDemo{ public static void main(String arsg[]){ Info< String> i = null; i = new InfoImpl< String>("Candy") ; // 通过子类实例化对象 System.out.println("test:" + i.getVar()) ; } };
3、泛型数组
public class GenericsDemo{ public static void main(String args[]){ Integer i[] = fun1(1,2,3,4,5,6) ; fun2(i) ; } public static < T > T[] fun1(T...arg){ return arg ; // 返回泛型数组 } public static < T > void fun2(T param[]){ for(T t:param){ System.out.print(t + "、") ; } } };
4、通配符
class Info< T >{ private T var ; public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ return this.var.toString() ; } }; public class GenericsDemo14{ public static void main(String args[]){ Info< String> i = new Info< String>() ; i.setVar("test") ; fun(i) ; } public static void fun(Info< ?> temp){ // 可以接收任意的泛型对象 System.out.println("内容:" + temp) ; } };
注:通配符类型 List<?> 与原始类型 List 和具体类型 List<String>都不相同,List<?>表示这个list内的每个元素的类型都相同,但是这种类型具体是什么我们却不知道。List<?>和List<Object>可不相同,由于Object是最高层的超类,List<Object>表示元素可以是任何类型的对象,但是List<?>不是这个意思。
5、受限类型
class Info< T >{ private T var ; public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ return this.var.toString() ; } }; public class GenericsDemo17{ public static void main(String args[]){ Info< Integer> i1 = new Info< Integer>() ; Info< Float> i2 = new Info< Float>() ; i1.setVar(30) ; i2.setVar(30.1f) ; fun(i1) ; fun(i2) ; } public static void fun(Info< ? extends Number> temp){ // 只能接收Number及其Number的子类 System.out.print(temp + "、") ; } };
6、泛型擦除
Java的泛型在编译阶段实际上就已经被擦除了。Java1.5引入泛型的最大压力来自于没有泛型的容器API相比起C++的标准模板库来太难用,太多不必要的显式转型,完全违背了DRY原则也缺乏精细的类型检查。但Java与C++不同,C++的对象没有公共父类,不使用泛型根本无法建立一个能存放所有类型的容器,所以必须在费大力气在编译后的运行代码中支持泛型,保留泛型信息自然是顺水推舟。而Java所有对象都有一个共同父类Object,当时已有的容器实现已经在运行期表现良好。所以Sun的考虑是加入一层简单的编译期泛型语法糖进行自动转换和类型检查,而在编译后的字节码中则擦除掉泛型信息,仍然走Object容器的旧路。这种升级方案对jdk的改动是最小的,Runtime根本不用改,改编译器就行了。
7、链式调用
public class Builder{ publicBuilder change(S left, E right){ // 省略实现 } public static void main(String[] args) { new Builder ().change("6", 6).change(6, 6.0f).change(6.0f, 6.0d); }}
上例中方法参数从String-int变到int-float,再变为float-double,这样的泛型在设计链式调用的方法的时候,特别是定义DSL语法的时候特别有用。
8、泛型递归
class Wrapper> implements Comparable > { @Override public int compareTo(Wrapper wrapper) { return 0; } }
对象E由包装器Wrapper所包装,但是,E也必须是一个包装器,这正是包装器的递归;同时,包装器也实现了一个比较接口,使得两个包装器可以互相比较大小。