什么是泛型?
泛型是程序设计语言的一种特性。允许程序员在强类型程序设计语言中编写代码时定义一些可变部分,那些部分在使用前必须作出指明。泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
我们为什么要使用泛型?
我们在编写程序时,经常遇到两个模块的功能非常相似,只是一个是处理int数据,另一个是处理string数据,或者其他自定义的数据类型,但我们没有办法,只能分别写多个方法处理每个数据类型,因为方法的参数类型不同。然而,泛型可以很轻松的解决这个问题。
用一个小小的例子简单看看:
public class Point <T>{ private T var; public T getVar(){ return var; } public void setVar(T var){ this.var=var; } }
public class test { public static void main(String[] args) { Point<String> p1 = new Point<String>(); p1.setVar(30 + ""); Point<Integer> p2 = new Point<Integer>(); p2.setVar(30); System.out.println(p1.getVar()); System.out.println(p2.getVar()); } }
运行结果如下:
从代码中可以很明显的看出泛型的优势。
同时,泛型可以使程序操作更加安全,可以避免发生类转换异常。当然还可以提高代码重用率。
泛型的基本应用
泛型的定义:
类定义:
【访问权限】 class 类名称 <泛型类型标识1,泛型类型标识2,……,泛型类型标识n>{
【访问权限】 泛型类型标识 变量名称;
【访问权限】 泛型类型标识 方法名称(){};
【访问权限】 返回值类型声明 方法名称(泛型类型标识 变量名称){};
}
对象定义:
类名称<具体类> 对象名称=new 类名称<具体类>();
注意:
- 在上面的例子中,Point类中使用了"<T>",T表示此类型是由外部调用本类时指定的,使用任意字母均可,如<A>、<Y>都可以,为了突出type(表示类型)才使用的T。
- 另外,泛型是无法指定基本数据类型的,必须设置成一个类,因此在设置一个数字时就必须使用包装类。
- 如果设置的内容与泛型所指定的类型不一致,则会在编译时出错。
- 可以在声明类时指定多个泛型类型。如class A<K,V>{}
- 在泛型应用中最好在声明类对象时指定好其内部的数据类型,如Info<String>,否则在使用时会出现不安全操作的警告信息。(不影响程序运行)
通配符的使用:
在泛型类的操作中,在进行引用传递时,泛型类型必须匹配才可以传递。
例如将上面的例子改成:
public class test { public static void main(String[] args) { Point<String> p1 = new Point<String>(); p1.setVar(30 + ""); fun(p1); } private static void fun(Point<Object> p1) { System.out.println(""+p1.getVar()); } }
会有如下的错误提示:
另外,我们还可以直接去掉<Object>,可正常运行。但是,不指定泛型类型不符合习惯,因此引入了通配符“?”,表示接收此类型的任意泛型对象。修改如下:
public class test { public static void main(String[] args) { Point<String> p1 = new Point<String>(); p1.setVar(30 + ""); fun(p1); } private static void fun(Point<?> p1) { System.out.println(""+p1.getVar()); } }
注意:如果使用"?"接收泛型对象时,则不能设置被泛型指定的内容。如:Point<?> p1 = new Point<String>();
受限泛型:
泛型上限使用extends关键字声明,表示泛型的类型可能是所指定的类型或者是此类型的子类。
泛型下限使用super进行声明,表示泛型的类型可能是所指定的类型,或者是此类的父类,或是Object类。
具体格式:
设置上限:(声明对象)类名称<? extends 类> 对象名称 (定义类)[访问权限] 类名称<泛型标识 extends 类>
设置下限:(声明对象)类名称<? super 类> 对象名称 (定义类)[访问权限] 类名称<泛型标识 super 类>
同样以最上面的例子做修改:
public class test { public static void main(String[] args) { Point<Integer> p1 = new Point<Integer>(); p1.setVar(30 ); fun(p1); } private static void fun(Point<? extends Number> p1) { System.out.println(""+p1.getVar()); } }
运行结果如下:(可正常运行)
注意:
一个类的子类可以通过对象的多态性为其父类实例化,但是在泛型操作中,子类的泛型类型是无法使用父类的泛型类型接收的,
如:
public static void main(String[] args) { Point<Integer> p1 = new Point<Integer>(); Point<Number> p2 = new Point<Number>(); p2=p1; }
编译时会出错:
这里为什么不能向上转型呢?
如果将子类泛型变为父类泛型,则表示扩大了子类的内容。打个比方:p1和p2由于类型的不同,p2相当于商场的全部商品,p1相当于个人购买的商品,如果p2=p1就相当于在个人购买商品中加入了商城的全部商品,这是基本不可能的。
泛型接口:
格式:【访问权限】 interface 接口名称 <泛型标识>
interface info<T>{ public T getVar(); }
泛型接口的实现方式有两种:
- 在子类的定义上声明泛型类型
- 直接在接口中指定具体类型
下面分别实现(第一种)
interface info<T>{ public T getVar(); } class Point <T> implements info <T>{ private T var; public Point(T var){ this.setVar(var); } public T getVar(){ return var; } public void setVar(T var){ this.var=var; } }
public class test { public static void main(String[] args) { info<String> i=null; i=new Point<String>("hehe"); System.out.println(""+i.getVar()); } }
运行结果:
(第二种)
interface info<T>{ public T getVar(); } class Point implements info<String>{ private String var; public Point(String var){ this.setVar(var); } public String getVar(){ return var; } public void setVar(String var){ this.var=var; } }
public class test { public static void main(String[] args) { info<String> i=null; i=new Point("hehe"); System.out.println(""+i.getVar()); } }
运行结果:
泛型方法
泛型方法的定义与其所在的类是否是泛型类是没有任何关系的。
定义:【访问权限】<泛型标识> 泛型标识 方法名称(【泛型标识 参数名称】)
如:public<T> T fun(T t){ return t;}
个人感觉泛型方法的使用与一般方法的使用并无太大的区别。
泛型的嵌套
简单的讲就是在一个类的泛型中指定另外一个类的泛型。用一个简单的实例就能明白了。
class info<T,V>{ private T var; private V value; public info(T var,V vanue){ this.setVar(var); this.setValue(vanue); } public T getVar(){ return var; } public void setVar(T var){ this.var=var; } public V getValue(){ return value; } public void setValue(V value){ this.value=value; } } class Demo <S>{ private S info; public Demo(S info){ this.setInfo(info); } public S getVar(){ return info; } public void setInfo(S info){ this.info=info; } }
public class test { public static void main(String[] args) { Demo<info<String,Integer>> d=null;//将info作为泛型类型 info<String,Integer> i=null;//info要指定两个两个泛型类型 i=new info<String,Integer>("123",456); d=new Demo<info<String,Integer>>(i);//在demo类中设置info类对象 System.out.println(""+d.getVar().getVar()); System.out.println(""+d.getVar().getValue()); } }
运行结果: