其实Java的泛型和C#的泛型是一样的道理,说白了就是“类型参数化”,没什么神秘的,所以这篇就说说Java泛型的一些事!
一、泛型的好处
避免拆装箱,提高程序性能
复用代码
类型安全
二、泛型类
[访问修饰符] class 类名 <泛型1,泛型2,…> { 泛型1 泛型成员1; 泛型2 泛型成员2; //.... } 泛型1,泛型2,…>
//此处声明了一个包含泛型T的泛型类,T代表所有可能的类型,而T的实际类型在Generic类实例化时指定。class Generic{ private T f; //f为泛型成员 public void setF(T f) {//setF方法的参数类型为泛型T this.f = f; } public T getF() {//getF方法的返回类型为泛型T return f; }}
三、泛型接口
interface Info{ // 在接口上定义泛型 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 } class InfoImpl implements Info { // 定义泛型接口的子类 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 GenericsDemo24{ public static void main(String arsg[]){ Info i = null; // 声明接口对象 i = new InfoImpl ("汤姆") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };
四、泛型方法
class Demo{ publicT fun(T t){ // 可以接收任意类型的数据 return t ; // 直接把参数返回 } }; public class GenericsDemo26{ public static void main(String args[]){ Demo d = new Demo() ; // 实例化Demo对象 String str = d.fun("汤姆") ; // 传递字符串 int i = d.fun(30) ; // 传递数字,自动装箱 System.out.println(str) ; // 输出内容 System.out.println(i) ; // 输出内容 } };
五、泛型通配符
非受限通配:? (它和? extends Object是一样的):适配所有的类型
受限通配:? extends T (表示T或T的一个未知子类型):限定通配符匹配类型的上限
下限通配: ? super T (表示T或T的一个未知父类型):限定通配符匹配类型的下限
注意:
多接口限制虽然Java泛型简单的用 extends 统一的表示了原有的 extends 和 implements 的概念,但仍要遵循应用的体系,Java 只能继承一个类,但可以实现多个接口,所以你的某个类型需要用 extends 限定,且有多种类型的时候,只能存在一个是类,并且类写在第一位,接口列在后面,也就是:<T extends SomeClass & interface1 & interface2 & interface3>
这里的例子仅演示了泛型方法的类型限定,对于泛型类中类型参数的限制用完全一样的规则,只是加在类声明的头部,如:
public class Demo{ //T类型就可以用Comparable声明的方法和Seriablizable所拥有的特性了 }
六、泛型擦除
在JAVA的虚拟机中并不存在泛型,泛型只是为了完善java体系,增加程序员编程的便捷性以及安全性而创建的一种机制,在JAVA虚拟机中对应泛型的都是确定的类型,在编写泛型代码后,java虚拟中会把这些泛型参数类型都擦除,用相应的确定类型来代替,代替的这一动作叫做类型擦除,而用于替代的类型称为原始类型,在类型擦除过程中,一般使用第一个限定的类型来替换,若无限定则使用Object.
泛型类(不带泛型限定)代码:
class Test{ private T t; public void show(T t) { }}
虚拟机进行翻译后的原始类型:
class Test{ private Object t; public void show(Object t) { }}