Java 泛型详解(超详细的java泛型方法解析)
1. 为什么使用泛型早期的Object类型可以接收任意的对象类型但是在实际的使用中会有类型转换的问题。也就存在这隐患所以Java提供了泛型来解决这个安全问题。来看一个经典案例123456789101112publicstaticvoidmain(String[] args) {//测试一下泛型的经典案例ArrayList arrayList newArrayList();arrayList.add(helloWorld);arrayList.add(taiziyenezha);arrayList.add(88);//由于集合没有做任何限定任何类型都可以给其中存放for(inti 0; i arrayList.size(); i) {//需求打印每个字符串的长度,就要把对象转成String类型String str (String) arrayList.get(i);System.out.println(str.length());}}运行这段代码程序在运行时发生了异常Exception in thread main java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String发生了数据类型转换异常这是为什么由于ArrayList可以存放任意类型的元素。例子中添加了一个String类型添加了一个Integer类型再使用时都以String的方式使用导致取出时强制转换为String类型后引发了ClassCastException因此程序崩溃了。这显然不是我们所期望的如果程序有潜在的错误我们更期望在编译时被告知错误而不是在运行时报异常。而为了解决类似这样的问题在编译阶段就可以解决在jdk1.5后泛型应运而生。让你在设计API时可以指定类或方法支持泛型这样我们使用API的时候也变得更为简洁并得到了编译时期的语法检查。我们将第一行声明初始化ArrayList的代码更改一下编译器就会在编译阶段就能够帮我们发现类似这样的问题。现在再看看效果。1234ArrayListString arrayList newArrayList();arrayList.add(helloWorld);arrayList.add(taiziyenezha);arrayList.add(88);// 在编译阶段编译器就会报错这样可以避免了我们类型强转时出现异常。2. 什么是泛型泛型是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型。也就是说在泛型使用过程中操作的数据类型被指定为一个参数而这种参数类型可以用在类、方法和接口中分别被称为泛型类、泛型方法、泛型接口。注意:一般在创建对象时将未知的类型确定具体的类型。当没有指定泛型时默认类型为Object类型。3. 使用泛型的好处避免了类型强转的麻烦。它提供了编译期的类型安全确保在泛型类型通常为泛型集合上只能使用正确类型的对象避免了在运行时出现ClassCastException。4. 泛型的使用泛型虽然通常会被大量的使用在集合当中但是我们也可以完整的学习泛型只是。泛型有三种使用方式分别为泛型类、泛型方法、泛型接口。将数据类型作为参数进行传递。4.1 泛型类泛型类型用于类的定义中被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种集合框架容器类如List、Set、Map。泛型类的定义格式修饰符 class 类名代表泛型的变量 { }怕你不清楚怎么使用这里我还是做了一个简单的泛型类123456789101112131415161718/*** param T 这里解释下T中的T:* 此处的T可以随便写为任意标识常见的有T、E等形式的参数表示泛型* 泛型在定义的时候不具体使用的时候才变得具体。* 在使用的时候确定泛型的具体数据类型。即在创建对象的时候确定泛型。*/publicclassGenericsClassDemoT {//t这个成员变量的类型为T,T的类型由外部指定privateT t;//泛型构造方法形参t的类型也为TT的类型由外部指定publicGenericsClassDemo(T t) {this.t t;}//泛型方法getT的返回值类型为TT的类型由外部指定publicT getT() {returnt;}}泛型在定义的时候不具体使用的时候才变得具体。在使用的时候确定泛型的具体数据类型。即在创建对象的时候确定泛型。例如GenericString genericString new GenericString(helloGenerics);此时泛型标识T的类型就是String类型那我们之前写的类就可以这么认为123456789publicclassGenericsClassDemoString {privateString t;publicGenericsClassDemo(String t) {this.t t;}publicString getT() {returnt;}}当你的泛型类型想变为Integer类型时也是很方便的。直接在创建时T写为Integer类型即可GenericInteger genericInteger new GenericInteger(666);注意 定义的泛型类就一定要传入泛型类型实参么并不是这样在使用泛型的时候如果传入泛型实参则会根据传入的泛型实参做相应的限制此时泛型才会起到本应起到的限制作用。如果不传入泛型类型实参的话在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。即跟之前的经典案例一样没有写ArrayList的泛型类型容易出现类型强转的问题。4.2 泛型方法泛型方法是在调用方法的时候指明泛型的具体类型 。定义格式修饰符 代表泛型的变量 返回值类型 方法名(参数){ }例如12345678910111213141516/**** param t 传入泛型的参数* param T 泛型的类型* return T 返回值为T类型* 说明* 1public 与 返回值中间T非常重要可以理解为声明此方法为泛型方法。* 2只有声明了T的方法才是泛型方法泛型类中的使用了泛型的成员方法并不是泛型方法。* 3T表明该方法将使用泛型类型T此时才可以在方法中使用泛型类型T。* 4与泛型类的定义一样此处T可以随便写为任意标识常见的如T、E等形式的参数常用于表示泛型。*/publicT T genercMethod(T t){System.out.println(t.getClass());System.out.println(t);returnt;}调用方法时确定泛型的类型12345publicstaticvoidmain(String[] args) {GenericsClassDemoString genericString newGenericsClassDemo(helloGeneric);//这里的泛型跟下面调用的泛型方法可以不一样。String str genericString.genercMethod(hello);//传入的是String类型,返回的也是String类型Integer i genericString.genercMethod(123);//传入的是Integer类型,返回的也是Integer类型}这里我们可以看下结果:class java.lang.Stringhelloclass java.lang.Integer123这里可以看出泛型方法随着我们的传入参数类型不同他得到的类型也不同。泛型方法能使方法独立于类而产生变化。4.3 泛型接口泛型接口与泛型类的定义及使用基本相同。泛型接口常被用在各种类的生产器中。定义格式1修饰符 interface接口名代表泛型的变量 { }看一下下面的例子你就知道怎么定义一个泛型接口了123456/*** 定义一个泛型接口*/publicinterfaceGenericsIntefaceT {publicabstractvoidadd(T t);}使用格式1、定义类时确定泛型的类型123456publicclassGenericsImpimplementsGenericsIntefaceString {Overridepublicvoidadd(String s) {System.out.println(设置了泛型为String类型);}}2、始终不确定泛型的类型直到创建对象时确定泛型的类型123456publicclassGenericsImpTimplementsGenericsIntefaceT {Overridepublicvoidadd(T t) {System.out.println(没有设置类型);}}确定泛型123456publicclassGenericsTest {publicstaticvoidmain(String[] args) {GenericsImpInteger gi newGenericsImp();gi.add(66);}}5. 泛型通配符当使用泛型类或者接口时传递的数据中泛型类型不确定可以通过通配符?表示。但是一旦使用泛型的通配符后只能使用Object类中的共性方法集合中元素自身方法无法使用。