泛型详解(转)
普通泛型
- 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();
}
这样Lists.newArrayList();
智能的知道返回类型为PrepaidHistory
泛型是JDK1.5的新东西,总结了一下,以后备忘,
泛型也叫generics,泛型分泛型方法和泛型类,两种定义方式,泛型还有上界下界的说法,
先看看什么叫泛型方法和泛型类,一下是网上的一个解释,个人觉得已经讲的很清楚了:
2、我们将Dao层的类写成范型的形式,有两种写法:
其一、
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 get(ID id),由于它的参数和返回类型都用了范型,故要在返回类型T前强制转换,即<T,ID>。
其二,范型也可写成以下形式:
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,编译器无法保证向下类型转换的安全,所以这一句自然就无法编译了
posted on 2013-08-06 16:14 foxspecial 阅读(275) 评论(0) 编辑 收藏 举报