JAVA泛型
泛型是JDK1.5的新东西,总结一下,以后备忘,
泛型也叫generics,泛型分泛型方法和泛型类,两种定义方式,泛型还有上界下界的说法。
究其本质就是:定义类、接口、方法的时候不指定类型,而是等到创建的时候再指定类型,这样可以大大提高代码重用,java里面典型的泛型应用就是 List, 你可以定义ArrayList<Integer>,还可以定义ArrayList<String>等, 注意泛型必须是引用类型。
举例:我们将Dao层的类写成范型的形式,有两种写法:
1.泛型方法
package com.test; public class EntityDao1 { public <T> void add(T t){ //查询实体的代码 } public <T,ID> T get(ID id){ //.保存实体的代码 return null; } }
范型一般用于方法的参数或者方法的返回值,上面的写法,我们要使范型有效,就须在方法的返回类型前提前指定泛型类型(泛型声明)。其中,add(T t)的参数用了范型,它的返回值是void型,就在void 前提前声明,即加上<T>,这样函数体里面就可以使用T类型了。而T get(ID id),由于它的参数和返回类型使用了不同的范型,所以要提前声明两种泛型,即<T,ID>。
2.泛型类
package com.test; public class EntityDao2<T,ID> { public void add(T t){ //..保存实体的代码 } public T get(ID id){ //.查询实体的代码 return null; } }
这种形式,是把范型声明放在类中了,就不需每个方法都声明泛型。
看实际需要,哪种方法方便就用哪种吧!范型给Java编程带来了许多方便,好好利用,会达到事半功倍的效果。
再看看什么叫上界和下界:
上界用extends关键字声明,表示参数化的类型可能是所指定的类型,或者是此类型的子类。如下面的代码:
public void upperBound(List<? extends Date> list, Date date) { Date now = list.get(0); System.out.println("now==>" + now); //list.add(date); //这句话无法编译 list.add(null);//这句可以编译,因为null没有类型信息 }
为什么会无法编译呢,实际调用时传入的list可能是java.util.Date的某个子类的参数化类型,如:
public void testUpperBound() { List<Timestamp> list = new ArrayList<Timestamp>(); Date date = new Date(); upperBound(list,date); }
也就是说,现在upperBound方法中实际的list是List<Timestamp>,向它添加一个Date类型,肯定是不行的。相反,读取数据时,不管实际的list是什么类型,但可以知道它至少会返回一个Date类型,所以用foreach,get等没有问题。
那么如何解决呢,可以使用泛型方法
public <T extends Date> void upperBound2(List<T> list, T date) { list.add(date); }
这里方法声明中的T作为一种参数化信息,会存储在java字节码中,T的实际类型由调用时的参数决定的。比如:
public void testUpperBound2() { List<Timestamp> list = new ArrayList<Timestamp>(); Date date = new Date(); Timestamp time = new Timestamp(date.getTime()); upperBound2(list,time); //upperBound2(list,date);//这句同样无法编译 }
上面代码中的list的类型参数决定了方法中T的类型,所以会看到注释掉的内容不能编译。而换成这样:
List<Date> list2 = new ArrayList<Date>(); upperBound2(list2,date);
编译就没有任何问题了。
下界
下界用super进行声明,表示参数化的类型可能是所指定的类型,或者是此类型的父类型,直至Object。如下面的代码:
public void lowerBound(List<? super Timestamp> list) { Timestamp now = new Timestamp(System.currentTimeMillis()); list.add(now); //Timestamp time = list.get(0); //不能编译 }
这又为什么不能通过编译呢,看看调用代码:
public void testLowerBound() { List<Date> list = new ArrayList<Date>(); list.add(new Date()); lowerBound(list); }
lowerBound方法中的List<? super Timestamp>表示这个list的参数类型可能是Timestamp或Timestamp的父类,如后面测试代码里,实际传入的是一个List<Date>类型。向List<Date>中add一个Timestamp肯定是没有问题的,但list.get()方法返回的对象类型可能是Date甚至是Object,你不能说list.get(0)返回的就是一个Timestamp,这里是向下类型转换了,编译器无法处理,所以这里不能编译。用java泛型实现的擦拭法解释,编译后会是如下的伪代码:
public void lowerBound(List list) { Timestamp now = new Timestamp(System.currentTimeMillis()); list.add(now); Timestamp time = (Timestamp)list.get(0); //① } public void testLowerBound() { List list = new ArrayList(); list.add(new Date()); lowerBound(list); }
代码①进行了强制类型转换,但实际添加进去的是一个Date类型,肯定会报ClassCastException,编译器无法保证向下类型转换的安全,所以这一句自然就无法编译了。
泛型实例
普通泛型
class Point<T>{ // 此处可以随便写标识符号,T是type的简称 private T var ; // var的类型由T指定,即:由外部指定 public T getVar(){ // 返回值的类型由外部决定 return var ; } public void setVar(T var){ // 设置的类型也由外部决定 this.var = var ; } }; public class GenericsDemo06{ public static void main(String args[]){ Point<String> p = new Point<String>() ; // 里面的var类型为String类型 p.setVar("it") ; // 设置字符串 System.out.println(p.getVar().length()) ; // 取得字符串的长度 } }; ---------------------------------------------------------- class Notepad<K,V>{ // 此处指定了两个泛型类型 private K key ; // 此变量的类型由外部决定 private V value ; // 此变量的类型由外部决定 public K getKey(){ return this.key ; } public V getValue(){ return this.value ; } public void setKey(K key){ this.key = key ; } public void setValue(V value){ this.value = value ; } }; public class GenericsDemo09{ public static void main(String args[]){ Notepad<String,Integer> t = null ; // 定义两个泛型类型的对象 t = new Notepad<String,Integer>() ; // 里面的key为String,value为Integer t.setKey("汤姆") ; // 设置第一个内容 t.setValue(20) ; // 设置第二个内容 System.out.print("姓名;" + t.getKey()) ; // 取得信息 System.out.print(",年龄;" + t.getValue()) ; // 取得信息 } };
通配符
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("it") ; // 设置内容 fun(i) ; } public static void fun(Info<?> temp){ // 可以接收任意的泛型对象 System.out.println("内容:" + 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 GenericsDemo17{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; // 声明Integer的泛型对象 Info<Float> i2 = new Info<Float>() ; // 声明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 + "、") ; } }; ---------------------------------------------------------- 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 ; //这句会出错 incompatible types } };
泛型接口
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 GenericsDemo24{ public static void main(String arsg[]){ Info<String> i = null; // 声明接口对象 i = new InfoImpl<String>("汤姆") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } }; ---------------------------------------------------------- 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 GenericsDemo25{ public static void main(String arsg[]){ Info i = null; // 声明接口对象 i = new InfoImpl("汤姆") ; // 通过子类实例化对象 System.out.println("内容:" + i.getVar()) ; } };
泛型方法
class Demo{ public <T> T 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) ; // 输出内容 } };
通过泛型方法返回泛型类型实例
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 GenericsDemo28{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; Info<String> i2 = new Info<String>() ; i1.setVar("HELLO") ; // 设置内容 i2.setVar("汤姆") ; // 设置内容 add(i1,i2) ; } public static <T> void add(Info<T> i1,Info<T> i2){ System.out.println(i1.getVar() + " " + i2.getVar()) ; } };
泛型数组
public class GenericsDemo30{ 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 GenericsDemo31{ 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()) ; } };
另:泛型方法不一定要通过参数来确定泛型准确类型,可以只通过返回值,比如:
public static <E> ArrayList<E> newArrayList() { return new ArrayList<E>(); } public List<PrepaidHistory> queryHistories(Long skyid,PrepaidHistoryType type, Date from, Date end) { ... return Lists.newArrayList(); }
这样通过 List<PrepaidHistory> 对应到 Lists.newArrayList(),推出泛型为PrepaidHistory类型
参考:
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845908.html
http://www.cnblogs.com/sunwei2012/archive/2010/10/08/1845938.html
http://baike.baidu.com/link?url=Qt_S4NncnnVTP26zmZfrrXIa7pXGp4uyICEmpITqsr4POZH7fyEhLDY1XuhB6TVRELj2BUpmrqz1qt5sb1o4Ka
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。