Java--泛型的原理以及使用场景

Java从1.5之后支持泛型,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。

入不支持泛型,则表现为支持Object,不是特定的泛型。

泛型是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样。

可以在集合框架中看到泛型的动机。例如,List类允许您向一个 List添加任意类的对象,即使最常见的情况List.add()。
因为 list.get() 被定义为返回 Object,所以一般必须将 list.get() 的结果强制类型转换为期望的类型,如下面的代码所示:

List list = new ArrayList();
list .add("obj");
String s = (String) list.get(0);

要让程序通过编译,必须将 get() 的结果强制类型转换为 String,并且希望结果真的是一个 String。但是有可能某人已经在该映射中保存了不是 String 的东西,这样的话,上面的代码将会抛出 ClassCastException。
理想情况下,您可能会得出这样一个观点,即 list 是一个 List,它将 String 键映射到 String 值。

泛型可以消除代码中的强制类型转换,同时获得一个附加的类型检查层,该检查层可以防止有人将错误类型的键或值保存在集合中。这就是泛型所做的工作。

 

泛型的好处

Java 语言中引入泛型是一个较大的功能增强。不仅语言、类型系统和编译器有了较大的变化,以支持泛型,而且类库也进行了大翻修,所以许多重要的类,比如集合框架,都已经成为泛型化的了。

这带来了很多好处:

1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。

没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。 

2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。

3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。

但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。

所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。

  Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。

    泛型在使用中还有一些规则和限制:
    1、泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
    2、同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
    3、泛型的类型参数可以有多个。
    4、泛型的参数类型可以使用extends语句,例如<T extends superclass>。习惯上成为“有界类型”。
    5、泛型的参数类型还可以是通配符类型。例如Class<?> classType = Class.forName(Java.lang.String);
    泛 型还有接口、方法等等,内容很多,需要花费一番功夫才能理解掌握并熟练应用。在此给出我曾经了解泛型时候写出的两个例子(根据看的印象写的),实现同样的 功能,一个使用了泛型,一个没有使用,通过对比,可以很快学会泛型的应用,学会这个基本上学会了泛型70%的内容。

 

泛型的使用场景

通配符

在开发中对象的引用传递是最常见的,但是在泛型操作中,进行引用传递的时候泛型必须匹配才可以传递,否则无法传递。

复制代码
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>() ; // 使用String为泛型类型 i.setVar("MLDN") ; // 设置内容 fun(i) ; } public static void fun(Info<?> temp){ // 可以接收任意的泛型对象 System.out.println("内容:" + temp) ; } };
复制代码

使用?可以接受任意类型的数据,却无法进行修改,?w为通配符。

受限泛型

复制代码
class Info<T> { private T var; // 定义泛型变量  public T getVar() { return var; } public void setVar(T var) { this.var = var; } public String toString(){ // 直接打印  return var.toString(); } } public class GenericsDemo17 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Info<Integer> info1 = new Info<Integer>(); // 声明Integer的泛型对象  Info<Float> info2 = new Info<Float>(); // 声明Float的泛型对象 Info<String> info3 = new Info<String>(); info1.setVar(30); // 设置整数,自动装箱 info2.setVar(30.1F); // 设置小数,自动装箱  info3.setVar("俺是字符串,不能被受限的FUN组装"); fun(info1); fun(info2); // fun(info3); //受限了,不能调用这个  } /** * 可以接收任意的泛型对象(// 只能接收Number及其Number的子类) * @param temp */ public static void fun(Info<? extends Number> temp){ // 只能接收String或Object类型的泛型 //public static void fun(Info<? super String> temp){ System.out.println("内容:"+temp); } }
复制代码

不仅仅在使用过程中,也可以在定义类的时候指定泛型上限:

复制代码
class Info<T extends Number>{   // 此处泛型只能是数字类型 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 GenericsDemo19{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象  } };
复制代码

如果设置成Stirng类型就会出现错误:

GenericsDemo20.java:15: 类型参数 java.lang.String 不在其限制范围之内 Info<String> i1 = new Info<String>() ; // 声明Integer的 泛型对象

String 不是Number的子类,最高不能超过Number的子类。

设置下限

泛型适用于本类以及父类类型上的时候,必须使用泛型下限。

如下只能接受String以及String的父类。最低不能接受Stirng类及其父类以外的类。

复制代码
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 GenericsDemo21{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 声明String的泛型对象 Info<Object> i2 = new Info<Object>() ; // 声明Object的泛型对象 i1.setVar("hello") ; i2.setVar(new Object()) ; fun(i1) ; fun(i2) ; } public static void fun(Info<? super String> temp){ // 只能接收String或Object类型的泛型 System.out.print(temp + "、") ; } };
复制代码

注意:子类无法使用父类的泛型类型进行接受。

复制代码
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 GenericsDemo23{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 泛型类型为String Info<Object> i2 = null ; i2 = i1 ; } };
复制代码

就会爆如下错误:

GenericsDemo23.java:17: 不兼容的类型 找到: Info<java.lang.String> 需要: Info<java.lang.Object> i2 = i1 ; ^

泛型接口: 

在jdk1.5以后,不仅仅可以声明泛型类,也可以声明泛型接口,泛型接口很类似泛型类:

访问权限 +interface +接口名称 + <泛型标示>{}

泛型接口实现的两种方式

1:

复制代码
interface Info<T>{        // 在接口上定义泛型
    public T getVar() ;    // 定义抽象方法,抽象方法的返回值就是泛型类型 } class InfoImpl implements Info<String>{ // 定义泛型接口的子类 private String var ; // 定义属性 public InfoImpl(String var){ // 通过构造方法设置属性内容 this.setVar(var) ; } public void setVar(String var){ this.var = var ; } public String getVar(){ return this.var ; } }; public class GenericsDemo{ public static void main(String arsg[]){ Info i = null; // 声明接口对象 i = new InfoImpl("soyoungboy") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };
复制代码

2:

复制代码
interface Info<T>{ // 在接口上定义泛型 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型 } class InfoImpl<T> implements Info<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>("soyoungboy") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };
复制代码

泛型方法:

泛型方法定义:

访问权限 +<泛型标示>+泛型标示 方法名称(泛型标示 参数名称)

复制代码
class Demo{ public <T> T fun(T t){ // 可以接收任意类型的数据 return t ; // 直接把参数返回  } }; public class GenericsDemo{ public static void main(String args[]){ Demo d = new Demo()    ; // 实例化Demo对象 String str = d.fun("soyoungboy") ; // 传递字符串 int i = d.fun(30) ; // 传递数字,自动装箱 System.out.println(str) ; // 输出内容 System.out.println(i) ; // 输出内容  } };
复制代码

通过泛型方法返回泛型类的实例

复制代码
class Info<T extends Number>{ // 指定上限,只能是数字类型 private T var ; // 此类型由外部决定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo27{ public static void main(String args[]){ Info<Integer> i = fun(30) ; System.out.println(i.getVar()) ; } public static <T extends Number> Info<T> fun(T param){ Info<T> temp = new Info<T>() ; // 根据传入的数据类型实例化Info temp.setVar(param) ; // 将传递的内容设置到Info对象的var属性之中 return temp ; // 返回实例化对象  } };
复制代码

 如果同一方法参数使用泛型,应该保证泛型类型一致:

复制代码
class Info<T>{ // 指定上限,只能是数字类型 private T var ; // 此类型由外部决定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆写Object类中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo{ public static void main(String args[]){  Info<Integer> i1 = new Info<Integer>() ; Info<String> i2 = new Info<String>() ; i1.setVar(30) ; // 设置内容 i2.setVar("aoyoungboy") ; // 设置内容  add(i1,i2) ; } public static <T> void add(Info<T> i1,Info<T> i2){ System.out.println(i1.getVar() + " " + i2.getVar()) ; } };
复制代码

就会产生错误:

泛型】_泛型的其他应用\代码>javac GenericsDemo.java GenericsDemo29.java:19: 无法将 GenericsDemo 中的 <T>add(Info<T>,Info<T>) 应用 于 (Info<java.lang.Integer>,Info<java.lang.String>) add(i1,i2) ; ^

泛型数组

使用泛型方法的时候,也可以传递或者返回一个泛型数组:

复制代码
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[]){ // 输出 System.out.print("接收泛型数组:") ; for(T t:param){ System.out.print(t + "、") ; } } };
复制代码

 泛型嵌套:

复制代码
class Info<T,V>{ // 接收两个泛型类型 private T var ; private V value ; public Info(T var,V value){ this.setVar(var) ; this.setValue(value) ; } public void setVar(T var){ this.var = var ; } public void setValue(V value){ this.value = value ; } public T getVar(){ return this.var ; } public V getValue(){ return this.value ; } }; class Demo<S>{ private S info ; public Demo(S info){ this.setInfo(info) ; } public void setInfo(S info){ this.info = info ; } public S getInfo(){ return this.info ; } }; public class GenericsDemo{ public static void main(String args[]){  Demo<Info<String,Integer>> d = null ; // 将Info作为Demo的泛型类型 Info<String,Integer> i = null ; // Info指定两个泛型类型 i = new Info<String,Integer>("李兴华",30) ; // 实例化Info对象 d = new Demo<Info<String,Integer>>(i) ; // 在Demo类中设置Info类的对象 System.out.println("内容一:" + d.getInfo().getVar()) ; System.out.println("内容二:" + d.getInfo().getValue()) ; } };
复制代码
 
android中类似于定义Adapter的时候传入model的泛型

 

posted @ 2016-07-19 10:19  逊志  阅读(19549)  评论(0编辑  收藏  举报