java 泛型(Generic)

  java泛型(generic)

2016-07-11

问题

  1. 向集合存储元素存在安全性问题,即很可能不知道已有的集合中已经存储的元素的类型是什么,这时就不应该向该集合随便添加元素,否则与集合的设计的初衷相悖,因为集合存储的是同类型的元素,而且以后取集合中的元素不知道该转为什么类型。
  2. 从集合中获取元素需要强制类型转换,可能出现ClassCastException问题

    未使用泛型举例:

 

    说明:任何Object子类均可以存入Object集合,但是从集合中获取元素,则是Object对象,需要强制转换,可能抛异常。

意义

使用泛型能够限定集合中存放的元素类型,标记集合中的元素类型,对存入集合的元素进行类型检查,让集合中的元素类型一致。泛型就是“参数化类型”,类比于形参和实参的关系,泛型就是让原本具体类型进行参数化,在泛型具体化或者泛型调用的时候,将类型实参传给类型形参,例如String这个实参传给T形参。

使用

未使用泛型

 1 public void test1(){
 2         //未使用泛型
 3         List list=new ArrayList();
 4         list.add(1);
 5         //加入类型不一致
 6         list.add("one");
 7         for(int i=0;i<list.size();i++){
 8             //可能出现ClassCastException
 9             int num=(int) list.get(i);
10         }
11     }

使用泛型

 

 1 public void test2(){
 2         //使用泛型,保证了集合使用的安全性
 3         List<Integer> list=new ArrayList<>();
 4         list.add(1);
 5         //不能加入其它类型
 6 //        list.add("one");
 7         for(int i=0;i<list.size();i++){
 8             //不会出现ClassCastException
 9             int num=list.get(i);
10         }
11     }

 

自定泛型类、泛型接口、泛型方法
泛型类及方法的使用
 1 class Animal<T>{
 2     
 3 }
 4 
 5 //Cat继承Animal
 6 //指定T为Short,Cat为具体类,不是泛型类
 7 class Cat extends Animal<Short>{
 8 }
 9 
10 //泛型类Persion继承Animal
11 //还未指定T,Persion是泛型类
12 class Persion<T> extends Animal<T>{
13     private T t;
14     List<T> list=new ArrayList<>();
15     public T getT(){
16         return this.t;
17     }
18     public void setT(T t){
19         this.t=t;
20     }
21     //泛型方法
22     public <E> E change(E e){
23         return e;
24     }
25 }
26 
27 public class Generic_Use{
28     public static void main(String[] args) {
29         //泛型类使用
30         {
31             //在实例化泛型类时,未指定泛型的具体类型,则泛型的默认类型为Object
32             Persion persion=new Persion();
33             persion.setT("helloWorld");
34             //persion.getT() 返回Object类型  需要强制转换为String
35             String str=(String) persion.getT();
36         }
37         {
38             //在实例化泛型类时,指定了泛型的具体类型A,则所有出现泛型的地方均为类型A
39             Persion<String> persion=new Persion<>();
40             persion.setT("helloWorld");
41             //persion.getT() 返回String类型
42             System.out.println(persion.getT());
43             {
44                 //泛型方法的具体化
45                 //persion.change(11)均返回Integer类型
46                 System.out.println(persion.change(11));
47                 //通用的泛型方法具体化
48                 System.out.println(persion.<Integer>change(11));
49                 //出错 无法指定类泛型具体类型为Integer的方法又用String进行 具体化
50 //            System.out.println(persion.<Integer>change("12"));
51             }
52         }
53     }

 

 泛型接口的使用类似泛型类,可类比使用

泛型与继承

 1 public class Generic_extends {
 2     public static void main(String[] args) {
 3         {
 4             //普通类与继承
 5             Object object=null;
 6             String str="str";
 7             object=str;
 8             
 9             Object[] objects=null;
10             String[] strs=new String[]{"str1","str2"};
11             objects=strs;
12         }
13         
14         {
15             //泛型类与继承
16             List<Object> list=null;
17             List<String> list2=null;
18             //出错    List<Object> 不是List<String>的父类
19 //            list=list2;
20             {
21                 //证明
22                 //反证:若List<Object>是 List<String>的父类
23                 list.add(11);
24                 String str=list2.get(0);//会出错
25                 
26                 //结论:若A是B的父类,但是List<A>不是List<B>的父类
27             }
28         }
29     }
30 }

泛型的通配符

原则:对于集合的使用,则是严进宽出,即放入集合要类型准确一致,取出可以模糊取出

注意点:静态方法和catch块不能使用泛型

建议:参考C++中的模板编程思想

 1 public void test3(){
 2         //通配符?
 3         {
 4             //List<?>是所有List<对象> 的父类
 5             //List<?>可以指向任意的List<对象>实例对象,并取出其中的元素,但是不能放入入元素
 6             
 7             List<?> list=new ArrayList<>();
 8             List<Object> list2=new ArrayList<>();
 9             List<String> list3=new ArrayList<>();
10             list2.add(12);
11             list3.add("bbb");
12             list=list2;
13             list=list3;
14             
15             {
16                 //list取出存在list3的元素
17                 Iterator<?> iterator=list.iterator();
18                 while(iterator.hasNext()){
19                     System.out.println(iterator.next());
20                 }
21                 
22                 //list不能直接通过自己向他的子类放入元素
23                 //list向list3中存入元素
24 //            list.add("ccc");//出错
25                 
26                 //特例 空对象
27                 list.add(null);
28                 
29                 
30             }
31         }
32         
33         {
34             //边界通配符  ? extends A 
35             //允许集合中的元素类型是A及其子类(类型通配符上限 类比小于等于号<=)
36             
37             List<? extends Number> list4=new ArrayList<>();
38             List<Integer> list5=new ArrayList<>();
39             list5.add(12);
40             list4=list5;
41             //list4取出存在list5中的元素
42             System.out.println(list4.get(0));
43             //list4向list5中存入元素
44 //            list4.add(12);//出错
45         }
46         
47         {
48             //边界通配符 ? super A
49             //允许集合中的元素类型是A及其父类(类型通配符下限 类比大于等于号>=)
50             
51             List<? super Integer> list6=new ArrayList<>();
52             List<Integer> list7=new ArrayList<>();
53             list7.add(12);
54             
55             list6=list7;
56             //list6取出存在list7中的元素
57             System.out.println(list6.get(0));
58             //list6向list7中存入元素
59 //            list6.add(12);//出错
60             
61 //        list7=list6;//出错
62         }
63         
64         //结论:
65         //对于泛型,父类可以从子类中取元素,但是不能存元素到子类中
66         //或者说可以从通配符泛型类中取出元素,但是不能写入元素
67         //体现了,集合中的元素严进宽出,写入集合的元素需要具体类型,而读取集合的元素没有要求
68     }
69 }

泛型提高

 1 public void test4(){
 2         List<Integer> list=new ArrayList<>();
 3         List<String> list2=new ArrayList<>();
 4         
 5         System.out.println("list的类型="+list.getClass());
 6         System.out.println("list2的类型="+list2.getClass());
 7         //结果:
 8         //list的类型=class java.util.ArrayList
 9         //list2的类型=class java.util.ArrayList
10         
11     }

从上面程序可以看出方法test4中list和list2的实际运行类型是一致的。

这关系到泛型的类型擦除。

原因分析:泛型设计的初衷就是在程序编写的时候就能够进行类型检查,避免程序运行时出错。对于泛型类型检查通过后,所以在编译时,会将泛型的相关信息擦出,也就是说,成功编译过后的class文件中是不包含任何泛型信息的。其实就是好比C++中模板编程,所有同一个泛型的具体化对象实际均是同一类型,所有同一泛型的具体化对象其实是共享同一份代码,即母代码,可以类比java中类和实例之间的关系学习。

转载于:https://www.cnblogs.com/Isen/p/5659006.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值