概念
- 泛型(JDK1.5后引入),即“参数化类型”,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
- 泛型可以在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的。
- 类型参数的意义是告诉编译器这个集合中要存放实例的类型,从而在添加其他类型时做出提示,在编译时就为类型安全做了保证。
- 这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
泛型类
-
泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。
-
泛型接口在接口名后添加类型参数列表,比如 < T >,<>内的泛型标识可以随便写,多个参数之间用逗号隔开。
-
泛型类的语法格式:
class 类名称 <T1,T1>{ private T1 a; private T2 b; ... }
-
示例
class C<T1,T2>{ T1 a; T2 b; public C(T1 a,T2 b){ this.a = a; this.b = b; } public T1 get1(){ return a; } public T2 get2(){ return b; } } public class Test { public static void main(String[] args) { C<String,String> c1 = new C<String,String>("Java是世界上最好的语言",".cpp"); System.out.println("a:"+c1.get1()); System.out.println("b:"+c1.get2()); System.out.println(c1.get1() + c1.get2()); C<Integer,Integer> c2 = new C<Integer,Integer>(666,999); System.out.println("a="+c2.get1()); System.out.println("b="+c2.get2()); System.out.println("a+b=" + (c2.get1() + c2.get2())); //泛型在旧版本不可以相加,现在可以相加 } }
-
输出:
a:Java是世界上最好的语言 b:.cpp Java是世界上最好的语言.cpp a=666 b=999 a+b=1665
泛型接口
-
和泛型类一样,泛型接口在接口名后添加类型参数列表
-
格式
public interface 接口名<T> { public T fun(); }
-
示例:
interface I<T>{ abstract void printI(T t); } abstract class CA<T>{ T a; public CA(T a){ this.a = a; } public T get1(){ return a; } abstract void printCA(); } class CB<T,T2,T3> extends CA<T> implements I<T3>{ //继承CA,实现I T2 b; public CB(T a,T2 b){ super(a); this.b = b; } public T2 get2(){ return b; } void printCA() { System.out.println("泛型类可以继承泛型类"); } public void printI(T3 t) { System.out.println(t); } } public class Test { public static void main(String[] args) { CB<Integer,String,String> c = new CB<Integer,String,String>(666,"NB"); c.printCA(); System.out.println(c.get2() + c.get1()); c.printI("接口"); } }
-
输出
泛型类可以继承泛型类 NB666 接口
泛型方法
-
泛型方法,是在调用方法的时候指明泛型的具体类型 。定义泛型方法只需要在方法返回值前添加类型参数列表。
public <T> void fun(){ //... }
-
示例
class C{ //泛型方法 public <T> void PrinInfo(T t){ System.out.println(t); } //泛型方法的重载 public <T1,T2> void PrinInfo(T1 t,T2 t2){ System.out.println(t); System.out.println(t2); } } public class Test { public static void main(String[] args) { C c = new C(); c.PrinInfo("少壮不努力","老大徒伤悲"); //可以使用任何类型 c.PrinInfo(666); c.PrinInfo(3.1415926); } }
-
输出:
少壮不努力 老大徒伤悲 666 3.1415926
限制泛型的使用类型
-
当没有指定泛型继承的类型或接口时,默认使用extends Objext,所以默认情况下任何类型都可以做为参数传入
-
在定义泛型类别时,如果想要限制使用泛型类型时,只能用某个特定类型或者是其子类型才能实例化该类型时,可以在定义类型时,使用extends关键字指定这个类型必须是某个特定类型,继承某个类,或者实现某个接口
-
示例:
class C<T extends String>{ //限制类型 T a; public C(T a){ this.a = a; } public T getData(){ return a; } } public class Test { public static void main(String[] args) { C<String> c = new C<String>("我现在只能是字符串哦"); //只能是String类型 System.out.println(c.getData());; } }
泛型的通配符
-
有时候希望传入的类型有一个指定的范围,从而可以进行一些特定的操作。
-
无限制通配符 < ?>:要使用泛型,但是不确定或者不关心实际要操作的类型,可以使用无限制通配符。
-
上界通配符 < ? extends E>:在类型参数中使用 extends 表示这个泛型中的参数必须是 E 或者 E 的子类。
-
下界通配符 < ? super E>:在类型参数中使用 super 表示这个泛型中的参数必须是 E 或者 E 的父类。
-
示例
class Animal{ public void eat(){ System.out.println("不同的动物有不同的吃法"); } } class Dog extends Animal{ public void eat(){ System.out.println("啃骨头"); } } class erha extends Dog{ public void eat(){ System.out.println("吃沙发"); } } class C<T>{ T a; void print(){ System.out.println("a:"+a); } C(T a){ this.a = a; } } public class Test { public static void main(String[] args) { C<Animal> c1 = new C(new Animal()); C<Dog> c2 = new C(new Dog()); C<erha> c3 = new C(new erha()); C<String> c4 = new C("我是一个字符串"); C<?> c5; C<? extends Dog> c6; C<? super Dog> c7; c5 = c1; c5 = c2; c5 = c3; c5 = c4; c6 = c2; c6 = c3; c7 = c1; c7 = c2; } }