gpt4 book ai didi

Java泛型定义与用法实例详解

转载 作者:qq735679552 更新时间:2022-09-28 22:32:09 25 4
gpt4 key购买 nike

CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.

这篇CFSDN的博客文章Java泛型定义与用法实例详解由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.

本文实例讲述了java泛型定义与用法。分享给大家供大家参考,具体如下:

1. 泛型的由来

  。

先看如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.util.list;
import java.util.arraylist;
public class testgeneric {
     @suppresswarnings ({ "rawtypes" , "unchecked" })
     public static void main(string[] args) {
         list list = new arraylist();
         list.add( 1 );
         list.add( "1" );
         list.add( new object());
         system.out.println(list);
         // 取值
         integer var1 = (integer) list.get( 0 );
         string var2 = (string) list.get( 1 );
         object var3 = list.get( 2 );
         system.out.println(var1 + " " + var2 + " " + var3);
     }
}

运行结果:

[1, 1, java.lang.object@1db9742] 1 1 java.lang.object@1db9742 。

这段代码很简单,将整形、字符串、对象放进list集合中,然后逐一取出。可以看出,由于list接口在定义时并不知道元素的类型,因此默认为object,即任意类型元素进入list集合后都会自动装箱。而取值的过程更为复杂,所有取得的值都是装箱后的object对象,必须得知道每一个元素的初始类型才能拆箱。一般使用集合的时候,集合的元素往往都是具有共同特征的,比如同属于一类的----那么,如果一开始限定了list集合元素的类型,那么就可避免上述不规范操作。代码如下, 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.list;
import java.util.arraylist;
public class testgeneric {
     @suppresswarnings ( "unused" )
     public static void main(string[] args) {
         list<string> list = new arraylist<string>();
         // list.add(1);//报错
         // list.add(new object());//报错
         list.add( "1" );
         // 取值
         string var1 = list.get( 0 ); // 无需转换
     }
}

如此一来,便有了泛型集合的说法。实际上,查阅list接口的api会发现,list接口正是泛型接口,它可以接受一个类型参数e,若不传递参数,则默认是object类型.

2. 泛型类型的继承关系

  。

有如下功能的代码,实现打印任意集合的元素:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.list;
import java.util.arraylist;
import java.util.collection;
public class testgeneric{
     //打印任意集合元素
     public void print(collection<object> c){
      system.out.println(c);
     }
     public static void main(string[] args){
      list<string> list= new arraylist<string>();
      new testgeneric().print(list);
  }
}

输出:

testgeneric.java:11: 无法将 testgeneric 中的 print(java.util.collection<java.lang.object>) 应用于 (java.util.list<java.lang.string>)    new testgeneric().print(list);                     ^ 1 错误 。

很明显,意思就是传递的参数类型不匹配。难道string不是继承自object的吗?没错,string是继承自object的,但是list<string>与list<object>是截然不同的两个类型,两者之间没有任何继承关系。那如果真的要实现上面的功能,该如何呢?

2.1 类型通配符 。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.list;
import java.util.arraylist;
import java.util.collection;
public class testgeneric {
     // 打印任意集合元素
     public void print(collection<?> c) {
         system.out.println(c);
     }
     public static void main(string[] args) {
         list<string> list = new arraylist<string>();
         new testgeneric().print(list);
     }
}

程序正常执行,这里的?表示一个未知类型,这个未知类型与object不同,list<?>代表了所有的list<类型>的父类.

2.2 泛型方法 。

不只有通配符可以解决泛型继承的问题,若将上面的方法定义为泛型方法也具有同样的效果:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
import java.util.list;
import java.util.arraylist;
import java.util.collection;
public class testgeneric {
     // 打印任意集合元素
     public <t> void print(collection<t> c) {
         system.out.println(c);
     }
     public static void main(string[] args) {
         list<string> list = new arraylist<string>();
         new testgeneric().print(list);
     }
}

泛型方法的定义形式如下, 。

修饰符 <t,e> 返回值 方法名(形参) 。

其中<t,e>在修饰符的后面做为类型定义,为方法指明形参中需要用到的t,e类型是来自哪里。既然泛型方法和类型通配符都可以实现泛型中的继承,那么有什么区别?

2.3 泛型方法和通配符的区别 。

看如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import java.util.list;
import java.util.arraylist;
import java.util.collection;
public class testgeneric {
     // 打印任意集合元素
     public <e, t extends e> void print(collection<t> c1, collection<e> c2) {
         system.out.println(c1);
         system.out.println(c2);
     }
     public static void main(string[] args) {
         list<father> list1 = new arraylist<father>();
         list<father> list2 = new arraylist<father>();
         new testgeneric().print(list1, list2); // 传2个father类型
         list<child> list3 = new arraylist<child>();
         list<father> list4 = new arraylist<father>();
         new testgeneric().print(list3, list4); // t为child,e为father
         list<father> list5 = new arraylist<father>();
         list<child> list6 = new arraylist<child>();
         new testgeneric().print(list5, list6); // t为father,e为child,报错
     }
}
class father {
}
class child extends father {
}
class other {
}

上述泛型方法在定义t,e时已经指明了关系:t是e的子类,所以在传递参数的时候,t要么是e的子类,要么就是e本身,所以在传递关系不小心变为e exends t时,在第三次调用方法时报错了。而如果把上述代码换成?通配符的话,则不具有如此强的限定关系.

总之,泛型方法和?通配符都可以实现未知类型的继承,但是泛型方法主要强调多个未知类型之间的依赖关系。如果只是单纯用作成为一个通用类型的父类这一功能的话,两者都可以实现,反而?通配符较为简洁明了.

2.4 泛型参数上、下限的注意 。

看如下代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.list;
import java.util.arraylist;
import java.util.collection;
public class testgeneric {
     // 复制集合并返回原始集合的最后一个元素
     public <t> t copy(collection<t> des, collection<? extends t> src) {
         t lastelement = null ;
         for (t t : src) {
             lastelement = t;
             des.add(t);
         }
         return lastelement;
     }
     public static void main(string[] args) {
         list<number> des = new arraylist<number>();
         list<integer> src = new arraylist<integer>();
         src.add( new integer( 1 ));
         integer lastelement = new testgeneric().copy(des, src); //
         system.out.println(lastelement.getclass());
     }
}

输出:

testgeneric.java:18: 不兼容的类型 找到: java.lang.number 需要: java.lang.integer integer lastelement= new testgeneric().copy(des,src);//                                               ^ 1 错误 。

当调用完copy方法后,系统比对发现t类型为number,?类型为integer。所以函数返回的t类型是number了,所以根本不兼容integer。要修改上面的代码,有俩个办法, 。

方法1:

改为 。

?
1
number lastelement= new testgeneric().copy(des,src);

分析代码可以得出,?为t的子类,在方法中t=lastelement这句表现为多态,虽然返回的是t类型,但是多态的表现为?类型,即interger类型,调用lastelement.getclass()也可发现返回的是java.lang.integer类型,说明此处编译类型为t类型,实际运行类型为?类型。这就好比如下多态转换, 。

?
1
2
father f= new child();
child c=f; //此处一定报错,类型不兼容

虽然f的多态表现为子类child,但是上面一句连语法检测都过不了。这也就是为什么上面integer不能兼容number的原因了.

方法2:

改为 。

?
1
public <t> t copy(collection<? super t> des,collection<t> src)

这样一来,?类型变为了父类,t类型变为了子类,于是在方法中返回的t类型对象,即lastelement就不具有多态性了。泛型中的上下限是很有学问的,每次看源码时都会琢磨很久,但还是会在浩瀚的接口+泛型的设计中昏迷,这种设计真的完全是为了突出面向对象的特性,以后慢慢琢磨吧.

从这也再次可以看出?通配符在处理具有依赖关系的泛型方法中,显得过于灵活而会导致一些潜在的隐患.

希望本文所述对大家java程序设计有所帮助.

原文链接:https://blog.csdn.net/kkkkkxiaofei/article/details/18262049 。

最后此篇关于Java泛型定义与用法实例详解的文章就讲到这里了,如果你想了解更多关于Java泛型定义与用法实例详解的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com