泛型的概念和使用

来源:互联网 发布:oracle数据库入门 编辑:程序博客网 时间:2024/06/07 05:56


为什么要使用泛型

在JDK1.5之前,使用集合类中存在的问题
ArrayList list = new ArrayList();list.add(1);list.add(1L);list.add("abc");int i = (Integer)list.get(2)

编译时要强制类型转换而且,运行时会报错。
JDK1.5的集合类希望你在定义集合时,明确表示你要向集合中装哪种类型的数据,无法加入指定类型以外的数据
ArrayList<Integer> list = new ArrayList<Integer>();list.add(1);/*list.add(1L);list.add("abc");*/这两行代码在编译时就报告了语法错误。
而且在取数据的时候不需要再类型转换了。也就是说泛型解决了数据类型安全性问题,其主要原理是在类声明时通过一个标识表示类中某个属性的类型或者是某个方法的返回值及参数类型。这样在类声明或实例化时只需要指定好需要的具体类型即可。

泛型的应用

泛型类的定义

class Point<T>{  private T var;  public T getVar(){      return var;  }  public void setVar(T var){      this.var = var;  }}
上面代码中的Point类在声明时使用了<T>的形式,T表示此类型是由外部调用本类时指定的,这里使用任何字母都可以。类中定义的var属性的类型也是T,这就表示var这个属性的类型也是外部来决定的,不是固定类型。同理,setter方法中的参数类型及getter方法中的返回值类型也由外部指定。
使用Point类将var类型设置成证整数:
public class Test {        public static void main(String[] args) {                Point<Integer> p = new Point<Integer>();                p.setVar(30);                System.out.println(p.getVar());                }}

输出结果为30.
以上程序将Point类中的var属性设置成Integer类型,所以在声明及实例化对象时使用Point<Integer>相当于setter和getter方法变成了以下格式:
public Integer getVar() {return var;}public void setVar(Integer var) {this.var = var;}

为什么不将Integer设置成int,是因泛型的指定是无法使用基本数据类型的,必须设置成一个类,所以设置基本类型需要用到他们的包装类。

泛型中的构造方法

public class Point<T> {private T var;public Point(T var){this.var = var;}public T getVar() {return var;}public void setVar(T var) {this.var = var;}}

public class Test {        public static void main(String[] args) {        Point<Integer> p = new Point<Integer>(100);        System.out.println(p.getVar());        }}

程序运行结果为100,泛型声明只是在类上定义,与构造方法无关。

泛型的安全警告

在泛型应用的时候,最好在定义对象时指定好数据类型,如果不指定就会出现安全警告。
public static void main(String[] args) {                Point p = new Point();//出现安全警告                p.setVar(100);//出现安全警告                System.out.println(p.getVar());}
虽然出现了警告,但是并不影响程序运行,因为在泛型的操作中如果没有指定类型,则统一用Object类型接收,所以以上程序的var属性实际上就变成了Object的类型。

泛型的传递在开发中很常见,在引用传递时泛型类型必须匹配才可以传递,否则无法传递,如下代码:
public class Test {public static void main(String[] args) {                Point<String> p = new Point<String>();                p.setVar("abc");                print(p);//编译报错,无法传递泛型}public static void print(Point<Object> p){                System.out.println(p.getVar());}}
虽然String是Object的子类,但是在进行引用传递时也同样无法进行操作,如果此时想让程序正确的执行,必须将print()方法中参数泛型类型改为String,或者不指定泛型。

泛型的上限和下限

在引用传递中,可以对泛型对象设置范围上限和范围下限。范围上限用extends关键字声明,表示泛型的类型可能是所指定的类型或者是这个类型的子类。而范围下限使用super进行声明,表示泛型的类型可能是所指定的类型,或者是此类型的父类型,或是Object类。

1.泛型的上限

假设一个方法中能接受的泛型对象只能是数字类型,则在定义这个方法参数接受对象的时候就必须指定泛型的上限。因为所有的数字包装类都是Number的子类,所以代码如下
public class Test {public static void main(String[] args) {                Point<Integer> p = new Point<Integer>();                Point<Double> p1 = new Point<Double>();                p.setVar(100);                p1.setVar(100.1);                print(p);                print(p1);}public static void print(Point<? extends Number> p){                System.out.println(p.getVar());}}
运行结果为
100
100.1
如果定义一个泛型类型为String的对象则无法传递进print()方法。

2.泛型的下限

当使用的泛型只能在本类或者其父类类型上应用时,就必须使用泛型的范围下限进行配置:
public class Test {public static void main(String[] args) {                Point<String> p = new Point<String>();                Point<Object> p1 = new Point<Object>();                p.setVar("abc");                p1.setVar(new Object());                print(p);                print(p1);}public static void print(Point<? super String> p){                System.out.println(p.getVar());}}
运行结果为:
abc
java.lang.Object@958bb8
如果定义一个泛型不为String或者Object类型的对象就无法传递进print()方法。

泛型数组

使用泛型方法时,也可以传递或返回一个泛型数组,接受和返回泛型数组代码如下:
public class Test {public static void main(String[] args) {                Integer[] i = getArray(1, 2, 3, 4, 5);                print(i);}public static <T> T[] getArray(T... arr) {                return arr;}public static <T> void print(T[] p) {                for (T t : p) {                    System.out.print(t + " ");}}}

运行结果为1 2 3 4 5
以上程序从getArray()返回一个泛型数组,然后将泛型数组内容交给print()方法打印出来。

0 0
原创粉丝点击