首页 > 学院 > 开发设计 > 正文

java泛型

2019-11-14 21:13:18
字体:
来源:转载
供稿:网友
java泛型引言

泛型是指参数化类型的能力,可以定义泛型类型的类、接口或方法,随后编译器会用具体的类型来替换它

使用泛型的主要优点是:能够在编译时而不是在运行时检测错误

package java.lang; public interface Comparable { //JDK1.5之前    public int compareTo(Object o);}package java.lang; public interface Comparable<T> { //JDK1.5之后    public int compareTo(T o);}

新泛型类型在编译时检测到可能的错误:

Comparable c = new Date();System.out.PRintln(c.compareTo("red"));Comparable<Date> c = new Date();System.out.println(c.compareTo("red"));

泛型类型必须是引用类型,不能用像int、double或char这样的基本类型来替换泛型类型:

ArrayList<int> intlist = new ArrayList<int>(); //error

必须使用:

ArrayList<Integer> intList = new ArrayList<Integer>();

java会自动打包操作:

ArrayList<Integer> intList = new ArrayList<Integer>();intList.add(5); //java会自动地将5包装为new Integer(5)
定义泛型类和接口

下面看一个泛型类的例子:

public class GenericStack<E> {    ArrayList<E> list = new ArrayList<E>();        public int getSize() {        return list.size();    }        public E peek() {        return list.get(getSize() - 1);    }        public void push(E o) {        list.add(o);    }        public E pop() {        E o = list.get(getSize() - 1);        list.remove(getSize() - 1);        return o;    }    public boolean isEmpty() {        return list.isEmpty();    }}
View Code

向栈中添加元素:

GenericStack<String> stack1 = new GenericStack<String>();stack1.push("London");stack1.push("Paris");stack1.push("Berlin");GenericStack<Integer> stack2 = new GenericStack<Integer>();stack2.push(1);stack2.push(2);stack2.push(3);
定义泛型方法
public static void main(String args[]){    Integer[] integers = {1, 2, 3, 4, 5};    String[] strings = {"London", "Paris", "New York", "Austin"};    print(integers);    print(strings);}    public static <E> void print(E[] list) {    for(int i = 0; i < list.length; i++)        System.out.print(list[i] + " ");        System.out.println();}
通配泛型

下面的例子说明了为什么要使用通配泛型:

public class Main{    public static void main(String args[])    {        GenericStack<Integer> intStack = new GenericStack<Integer>();        intStack.push(1);        intStack.push(2);        intStack.push(-2);        System.out.print("The max number is " + max(intStack));    }        public static double max(GenericStack<Number> stack) {        double max = stack.pop().doubleValue();                while(!stack.isEmpty()) {            double value = stack.pop().doubleValue();            if(value > max)                max = value;        }        return max;    }        }

标记行会产生编译错误,因为intStack不是GenericStack<Number>的实例,尽管Integer是Number的子类型,但是GenericStack<Integer> 并不是 GenericStack<Number> 的子类型,为了避免这个问题,可以使用通配泛型类型 ,通配泛型类型有三种形式:

非受限通配:? (它和? extends Object是一样的)

受限通配:? extends T (表示T或T的一个未知子类型)

下限通配: ? super T (表示T或T的一个未知父类型)

使用受限通配修改后的代码如下:

public class Main{    public static void main(String args[])    {        GenericStack<Integer> intStack = new GenericStack<Integer>();        intStack.push(1);        intStack.push(2);        intStack.push(-2);        System.out.print("The max number is " + max(intStack));    }        public static double max(GenericStack<? extends Number> stack) {        double max = stack.pop().doubleValue();                while(!stack.isEmpty()) {            double value = stack.pop().doubleValue();            if(value > max)                max = value;        }        return max;    }        }

再看下面的一个例子:

public class Main{    public static void main(String args[])    {        GenericStack<Integer> intStack = new GenericStack<Integer>();        intStack.push(1);        intStack.push(2);        intStack.push(-2);        print(intStack);    }    public static void print(GenericStack<?> stack) {        while(!stack.isEmpty()) {            System.out.print(stack.pop() + " ");        }    }    }

什么时候使用下限通配?看下面的例子:

public class Main{    public static void main(String args[])    {        GenericStack<String> stack1 = new GenericStack<String>();        GenericStack<Object> stack2 = new GenericStack<Object>();        stack2.push("Java");        stack2.push(2);        stack1.push("Sun");        add(stack1, stack2);        print(stack2);    }        public static<T> void add(GenericStack<T> stack1,            GenericStack<? super T> stack2) {        while(!stack1.isEmpty()) {            stack2.push(stack1.pop());        }    }        public static void print(GenericStack<?> stack) {        while(!stack.isEmpty()) {            System.out.print(stack.pop() + " ");        }    }    }
消除泛型和对泛型的限制

泛型是一种称为类型消除的方法实现的,泛型信息在运行时是不可用的,这种方法可以使泛型代码向后兼容使用原始类型的遗留代码

泛型存在于编译时。一旦编译器确认泛型类型是安全使用的,就将它转换为原始类型

例如下面的代码:

ArrayList<String> list = new ArrayList<String>();list.add("Oklahoma");String state = list.get(0);

翻译成如下的代码的原始类型:

ArrayList list = new ArrayList();list.add("Oklahoma");String state = (String)list.get(0);

使用泛型类型是有一些限制的:

限制1、不能使用new E()

不能使用泛型类型参数创建实例:E object = new E()

限制2、不能使用new E()

不能使用泛型类型参数创建数组,如:E[] elements = new E[capacity];

可以通过创建一个Object类型的数组,然后将它的类型转化为E[]来规避这个限制,如:E[] elements = (E[]) new Object[capacity];

限制3、在静态环境中不允许类的参数是泛型类型

由于泛型类的所有实例都有相同的运行时类,所以泛型类的静态变量和方法是被它的所有实例所共享的,下面的代码非法:

public calss Test<E> {    public  static Void m(E o1) {    }    public static E o1;    static {        E o2;    }}

限制4、异常类不能是泛型的


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表