泛型
它是jdk1.5的新特性之一,是个安全机制。
表现形式:<指定具体的类型>。
好处:将运行时期的ClassCastException问题转移到了编译时期,同时也避免了强制类型转换的麻烦。
简单的来说,泛型就是类型参数传递。
什么时候使用泛型:当我们看到所要使用的类或者接口旁边有<>就要使用它了。
泛型存在于编译时期,用于检测所操作的引用数据类型,编译后就消失了,也即泛型檫除。既然檫除了,我们要想获取元素的类型可以通过存入的元素获取元素的类型,并用该类型对所取出的数据进行具体类型的指定,也即泛型的补偿。
下面就泛型在类,接口,方法,集合中的应用分别进行演示。另外对通配符的解释。
泛型类的应用:也即在自定义的类上加上泛型。注意:泛型要加在修饰符后,返回值前。它可以将运行期的问题转移到编译时期。
class Tool<T>{ //定义一个泛型类
private T obj;
public void setObject(T obj){
this.obj = obj;
}
public T getObject(){
return obj;
}
}
class Student{}
class Worker{}
class GenericDemo{
Tool<Student> t = new Tool<Student>();//应为Tool类加上了泛型,所以在创建对象时可以被指定为任意类型
t.setObject(new Student());
Student s = t.getObject();//泛型类可以避免强转
}
演示二:
class Demo<Q>{
public void show(Q q){
System.out.println(q);
}
public void print(Q q){
System.out.println(q);
}
}
class GenericDemo{
public static void main(String[] args){
Demo<String> d = new Demo<String>();//在创建对象时要明确什么类型,一旦确定,在传递时就要传入相应的类型,否则报错
d.show("asd");
d.print("haha");
d.print(new Integer(3));//编译失败。因为类类型已被确定为String类型,但我们可以重新创建一个对象来实现
Demo<Integer> d = new Demo<Integer>();
d.print(new Integer(3));//编译通过
}
}
什么时候使用泛型类:当类中引用数据类型不确定的时候使用。
方法泛型演示:
class Demo1<Q>{
public void show(Q q){ //show方法操作的类型一定要和Demo对象指定的类型一致
System.out.println(q);
}
public <T> void print(T q){ //print方法传递的值类型可以不与类类型指定的一致
System.out.println(q);
}
public static void method(Q q){
System.out.println(q); //编译失败,因为静态没有对象,所以不能访问类中的泛型,同时静态也不能访问非静态
}
public static <Z> void method(Z q){ //编译通过
System.out.println(q)
}
class Demo1{
public <Q> void show(Q q){ //show方法操作的类型可以任意传入
System.out.println(q);
}
public <T> void print(T q){ //print方法操作的类型可以任意传入
System.out.println(q);
}
}
class GenericDemo{
public static void main(String[] args){
Demo d = new Demo();
d.show("asd");
d.print("haha");
d.print(new Integer(3));//编译通过,应为方法中使用了泛型,具体传递什么类型是不确定的,同时方法中的泛型可以覆盖类中的泛型
}
}
注意:泛型要加在修饰符后,返回值前。它可以将运行期的问题转移到编译时期。
静态方法上是不可以访问类上定义的泛型,除非在泛型定义在该静态方法上才可以。
什么时候定义泛型方法:当方法要操作的引用数据类型不确定时可以用泛型来解决。
注意细节:在泛型方法中,不可以使用泛型接收到的具体类型的特有方法,因为要操作的类型是不确定的,不能使用具体的功能因为在泛型被檫除时,泛型上定义的都是Object类型的,所以可以使用Object的功能,因为这些功能所有的对象都具备。
泛型定义在接口上:
interface Inter<T>{
public void show(T t);
}
class InterImpl implements Inter<String>{ //接口的具体类型指定为String类型
public void show(String s){
System.out.println("show"+s);
}
}
class GenericDemo{
public static void main(String[] args){
InterImpl i = new InterImpl();
i.show("ass");
i.show(new Integer(2)); //编译失败,因为接口的泛型被定义为String类型
}
}
如果要解决编译失败的问题,我们可以在InterImpl类中加入泛型即可!
interface Inter<T>{
public void show(T t);
}
class InterImpl <T> implements Inter<T>{ //让接口的类型跟着类走
public void show(T s){
System.out.println("show"+s);
}
}
class GenericDemo{
public static void main(String[] args){
InterImpl<String> i = new InterImpl<String>();
i.show("ass"); //编译通过,因为在类InterImpl中加入了泛型,定义类型为String类型
InterImpl<Integer> i = new InterImpl<Integer>();
i.show(new Integer(2)); //编译通过,因为在类InterImpl中加入了泛型,定义类型为Integer类型
}
}
泛型在集合框架中的限定:在方法中的参数Collection<Student>说明只能接收存储学生对象的集合。
在方法中的参数Collection<?>说明能够接收任意对象的集合,?代表着任意类型。
在方法中的参数Collection<? extends Person>说明能够接收Person类或其子类对象的集合。
在方法中的参数Collection<? extends Person>说明能够接收Person类或其父类型对象的集合。