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<String> 不是List<Object>的父类
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中类和实例之间的关系学习。

时间: 2024-11-08 18:19:29

java 泛型(Generic)的相关文章

Java泛型Generic - Thinking in Java读书笔记

1.什么是泛型? 泛型就是可适用于很多的类,它实现了参数化类型type parameter的概念,参数化类型指可使用多种类型. 多态是一种泛化机制. 例如方法 A(Base b){}//Base是一个基类 这样方法A就可以接受从这个基类Base的任何子类作为参数.方法的参数也可以是一个接口,但是由于类的单继承体系和接口的约束( An interface still requires that your code works with that particular interface. ),不能

Java基础之Comparable接口, Collections类,Iterator接口,泛型(Generic)

一.Comparable接口, Collections类 List的常用算法: sort(List); 排序,如果需要对自定义的类进行排序, 那就必须要让其实现Comparable接口, 实现比较两个类大小的方法 shuffle(List); 随机排列 void reverse(List); 逆序排列(Linked效率较高) copy(); 复制集合, 前提是size()相同(长度, 和容量的区别) fill(List, Object);使用某个对象填充整个List binarySearch()

Java泛型通配符学习 —— Java Generic&#39;s Wildcards

Java Generic's wildcards is a mechanism in Java Generics aimed at making it possible to cast a collection of a certain class, e.g A, to a collection of a subclass or superclass of A. This text explains how. 理解:Java的泛型通配符机制旨在实现集合的类型转换.例如集合A,转换为A的子类集合或

JAVA学习笔记(五十六)- 泛型 Generic Types

泛型 Generic Types import java.util.ArrayList; import java.util.List; /* * 泛型 Generic Types * 集合泛型 * 类泛型 * 方法泛型 */ public class Test01 { public static void main(String[] args) { // 1.集合泛型,保证集合中元素的类型安全 List<Integer> nums = new ArrayList<Integer>(

Java之集合初探(二)Iterator(迭代器),collections,打包/解包(装箱拆箱),泛型(Generic),comparable接口

Iterator(迭代器) 所有实现了Collection接口的容器都有一个iterator方法, 用来返回一个实现了Iterator接口的对象 Iterator对象称作迭代器, 用来方便的实现对容器内的元素的遍历 迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构.迭代器通常被称为"轻量级"对象,因为创建它的代价小. Java中的Iterator功能比较简单,并且只能单向移动: (1) 使用方法iterator()要求容器返回一个I

java 泛型 窜讲

一.为什么使用泛型      复用性:泛型的本质就是参数化类型,因而使用编写的泛型代码可以被许多不同类型的对象所复用.      安全性:在对类型Object引用的参数操作时,往往需要进行显式的强制类型转换.这种强制类型转换需要在运行时才能被发现是否转换异常,通过引入泛型能将在运行时才能检查类型转换,提前到编译时期就能检查. 二.自定义泛型 java中自定义泛型分为三种:泛型类.泛型接口.泛型方法. 下面使用一个案例演示泛型类.泛型方法,泛型接口类似,所以不再演示. // 自定义泛型类publi

1月21日 - (转)Java 泛型

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

java泛型的讲解

java泛型 什么是泛型? 泛型(Generic type 或者 generics)是对 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类.可以把类型参数看作是使用参数化类型时指定的类型的一个占位符,就像方法的形式参数是运行时传递的值的占位符一样. 可以在集合框架(Collection framework)中看到泛型的动机.例如,Map 类允许您向一个 Map 添加任意类的对象,即使最常见的情况是在给定映射(map)中保存某个特定类型(比如 String)的对象. 因为 M

jdk学习之路---java泛型

1:java泛型的好处是可以实现类型检查,比较安全,可以实现功能的扩展化,增强功能. 2:泛型的概念就是参数化的类型,相当于方法中的形式参数一样,先做一个占位符然后再在使用的时候传递真正的参数进去. 3: package generic; /** * 自定义泛型类 * @author PC * */ public class GenericModel <T>{ private T data; public GenericModel(){ } public GenericModel(T data