泛型

来源:互联网 发布:icloud软件下载 编辑:程序博客网 时间:2024/05/28 23:10

0.泛型知识体系

Java泛型知识体系如下图所示:


1.泛型概论


1)泛型概念

JDK1.5出现的技术,是一种安全机制;再直白一点,泛型就是通过<>定义形式参数,专门用于接收具体的引用类型。另外,{}、[]、()、<>已经全部都有用处。

只要类型不确定就用泛型,使用时明确类型。


2)技术由来

集合中可存储任意类型对象,但是如果取出时调用具体对象特有方法时需要进行向下转型,如果存储对象类型不一致,转型过程中就出抛出ClassCastException异常,给程序带来不安全性。JDK1.5之后就出现了解决方案,即泛型技术。

如下列代码:

public class GenericTest{public static void main(String[] args){List ls = new ArrayList();ls.add("Tad");ls.add("Great");ls.add(23);Iterator it = ls.iterator();while(it.hasNext()){String str = (String)it.next();//执行到第3次时,出现问题System.out.println(str.length());}}}

解决方案就是泛型,在定义容器时完成类型确定,如果类型不匹配就会发生编译错误。


3)泛型关键词

(1)ArrayList:原始类型。

(2)ArrayList<E>:泛型类型;<E>:类型参数。

(3)ArrayList<String>:参数类型;String:实际类型参数。


4)泛型优点

(1)将运行时期的ClassCastException转移到编译时期进行检查并以编译失败体现,利于程序员解决问题,提高安全性。

(2)简化书写,避免类型强制转换,提高效率。


2.通配符与类型限定

1)通配符

构造参数化类型时,如果类型参数不确定,就写类型通配符?。

当操作的不同容器中的类型都不确定的时候,而且使用的都是元素从Object类中继承的方法,这时泛型就用通配符?表示。

public class GenericAdv{public static void main(String[] args){ArrayList<String> al1= new ArrayList<String>();al1.add("tad1");al1.add("tad2");al1.add("tad3");printColl(al1);ArrayList<Integer> al2 = new ArrayList<Integer>();al2.add(23);al2.add(23);al2.add(23);printColl(al2);}public static void printColl(ArrayList<?> al){Iterator<?> it = al.iterator();while(it.hasNext()){System.out.println(it.next());}}}

public static void printColl(Collection<?> al){}

通配符应用的具体体现。


2)通配符限定

明确具体类型代表一个类型,明确?代表类型,能不能限定只操作某个范围类型?
? extends E 接收E类型或者E的子类型,上限,可以使用E的所有方法:添加元素时用到,如Collection<? extends Person>。
? super E 接收E类型或E的父类型,从容器中取出元素,取出来的都能接收。

?相当于 ? extends Object,所以只能使用Object的方法。


3)类型参数上限与带有接口上限

public class Apple<T extends Number>{}

一个父类上限,多个接口上限。
public class Apple<T extends Apple && java.io.Serializable>{}

3.定义及使用泛型

1)定义及使用泛型接口

两种使用方法
(1)实现接口时,明确具体的类。

(2)实现接口时,也不明确具体的类。

//定义泛型接口interface Shower<G>{//声明是泛型类型,类型参数为Gpublic abstract void show(G g);}//实现泛型接口时明确具体类型class ShowerImplA implements Shower<Integer>{public void show(Integer g){System.out.println(g);}}//实现接口时不明确具体类型,泛型类+泛型接口class ShowerImplB<C> implements Shower<C>{public void show(C g){System.out.println(g);}} public class GenericInterface{public static void main(String[] args){ShowerImplA sib = new ShowerImplA();sib.show(23);//sib.show("Tad is a great person in the world!");ShowerImplB<String> sia = new ShowerImplB<String>();sia.show("abc");}}


2)泛型类

(0)早期做法(自定义泛型类)

package tad.blog.generic;class Teacher{}class Student{}class ObjectTools{private Object obj;public Object getObj(){return obj;}public void setObj(Object obj){this.obj = obj;}}public class LongAgo{public static void main(String[] args){ObjectTools ot = new ObjectTools();ot.setObj(new Teacher());Student stu = (Student)ot.getObj();}}

(1)泛型类声明及使用

class Generic<T>//声明是泛型,并且类型参数为T{public void info(){System.out.println("Hello world");}}public class GenericTest {public static void main(String[] args) {Generic<String> g = new Generic<String>();//泛型类实例时指明具体类型g.info();}}


(2)泛型类型派生类

当使用了泛型类之后,就可以为父类派生子类,但需要注意的是当使用父类时不能再包含类型形参。

3)泛型方法

public class GenericMethod{public static void main(String[] args){Tools<String> tool = new Tools<String>();tool.println("Tad is a great person in the world.");//tool.println(new Integer(23));//不能打印其它类,如果想要做到,就必须重新new对象。Tools<Integer> tool2 = new Tools<Integer>();tool2.println(new Integer(23));//tool2.println("Tad is a great person in the world.");//同样不可以}}class Tools<E>{public void println(E e){System.out.println(e.toString());}}

如果想要不重新new对象就改变可以使方法打印各种各样的数据,就需要用到方法的泛型。

方法的操作类型不确定,但不一定和调用该方法的对象指定的类型一致。
泛型定义在类上与泛型定义在方法上,作用域是不一样的。定义的位置不同。

方法泛型参数的定义位置是返回值前方修饰符后方。

public class GenericMethod{public static void main(String[] args){Tools<String> tools = new Tools<String>();tools.rawPrintln("Tad is a great person in the world!");//tools.rawPrintln(new Integer(23));//编译错误tools.println("Tad is a great person in the world");//要求传入新的类型参数。tools.println(new Integer(23));//也是ok的}}class Tools<E>{public void rawPrintln(E e){System.out.println(e.toString());}public <T> void println(T t){System.out.println(t.toString());}}

泛型定义小插曲

(1)泛型类型不能访问类上定义的泛型,如果需要泛型只能定义在方法上。因为类上泛型用到时是在类进行实例化时,而静态方法的调用是不用实例化。


4)类库中的泛型

只要在使用类或或者接口时,该类或接口在API文档描述中带着<>就需要使用,写代码时直接加上,而不是写完再加上,文档中会说明。
保证两边一致。
ArrayList<Object> al = new ArrayList<String>();

ArrayList<String> al = new ArrayList<Object>();


5.泛型擦除和转换

泛型是编译器上的技术,编译时对用指定类型对代码检查,检查不通过,编译失败,检查通过完成之后生成class文件中没有泛型,此就是泛型擦除。

运行时可根据具体元素对象获取其具体类型,并用该类型对元素进行转换。

0 0