和Java泛型谈谈


泛型,把类型参数化。
泛型的命名规则:
不要小写字母表示泛型名字,虽然这也没什么错。如果可以的话,泛型就用“T”来表示。
还有就是类上的泛型和方法上的泛型,名字尽量不要相同。

它在JDK1.5之后出现,主要的作用是解决安全问题
比如下面的安全问题:

private static void method_1() {
        ArrayList al=new ArrayList();
        al.add("abc01");
        al.add("abc0991");
        al.add("abc014");
        al.add(4);
        Iterator it=al.iterator();
        while(it.hasNext()){
            String next=(String)it.next();
            System.out.println(next);
        }
    }

ArrayList可以添加任何类型的元素,该方法在程序编译时并不会出现问题。但是在迭代取值时,Integer类型的值无法转换为String,会出现ClassCastException异常。

而避免这种问题的,就是指定ArrayList的元素的类型,把类型参数化。比如这样:

ArrayList<String> al=new ArrayList<String>();
al.add("abc01");
al.add("abc0991");
al.add("abc014");
//al.add(4);    编译时提示错误

本例子中,泛型可以把一些错误提前到了编译时期,方便了调试。而且在迭代时,不再需要强制转化。

Iterator<String> it=al.iterator();
while(it.hasNext()){
    System.out.println(it.next());
}

1,泛型定义在类上
ArrayList类上的泛型

public class ArrayList<E> extends AbstractList<E>

ArrayList al=new ArrayList();
传递进去的类的泛型是String,而定义在类上的泛型,在整个类中都是有效的。
类上的泛型可以由一个也可以由多个:

class GenericForClass1<T>{
        private T temp;

        private void set(T t){
            this.temp=t;
        }

        private T get(){
            return temp;
        }

        private void print(){
            System.out.println(temp);
        }
    }

    private void generic_1() {
        GenericForClass1<Integer> generic=
                new GenericForClass1<Integer>();
        generic.set(1);
        generic.print();
    }
class GenericForClass2<T1,T2>{
        private T1 t1;
        private T2 t2;

        private void setT1(T1 t){
            this.t1=t;
        }

        private T1 getT1(){
            return t1;
        }

        private void setT2(T2 t){
            this.t2=t;
        }

        private T2 getT2(){
            return t2;
        }

        private void print(){
            System.out.println(t1+"----"+t2);
        }
    }

private void generic_1() {
        GenericForClass2<Integer,String> generic=
            new GenericForClass2<Integer,String>();
        generic.setT1(1);
        generic.setT2("ronaldo");
        generic.print();
    }

2,泛型定义在方法上

class GenericForClass1<T>{
        private T temp;

        private void set(T t){
            this.temp=t;
        }

        private T get(){
            return temp;
        }

        private void print(){
            System.out.println(temp);
        }
    }

泛型定义在类上后,操作的类型就固定了。比如下面的写法就有问题:

    GenericForClass1<Integer> generic=
                    new GenericForClass1<Integer>();
    eneric.set("1");//编译出错

为了让不同的方法操作不同的类型,我们可以不把泛型定义在类上,而是定义在方法上。
注意的是泛型如果定义在方法上,只对该方法是有效的。
如下:

class GenericForClass1{
        private <T>void show(T t){
            System.out.println(t);
        }
    }

private void generic_1() {
        GenericForClass1 generic=
                new GenericForClass1();
        generic.show("1");
        generic.show(1);
    }

当然也可以在类上定义泛型,而在方法上也定义泛型来操作不同类型。如:

class GenericForClass1<T>{
        private T t;

        private void set(T t){
            this.t=t;
        }

        private T get(){
            return t;
        }

        private void print(){
            System.out.println(t);
        }

        private <S>void show(S s){
            System.out.println(s);
        }
    }

private void generic_1() {
        GenericForClass1<Integer> generic=
                new GenericForClass1<Integer>();
        generic.set(1);
        generic.set("1");//编译错误,set方法的泛型和类是绑定的
        generic.print();
        generic.show("1");
    }

静态方法的泛型:

class Demo1<T>{     
        private void show(T t){
            System.out.println(t);
        }

        private <T>void set(T t){
            System.out.println(t);
        }

        //编译时会出现错误
        private static <T> void method(T t){
            System.out.println(t);
        } 
    } 

静态方法访问类上的泛型,编译出错。原因是,建立对象后才会有泛型。
比如ArrayList al=new ArrayList();
我们知道静态成员是先加载的。
既然静态方法无法访问类上的泛型,我们可以为它在方法上定义泛型。

private static <S>  void method(S s){
            System.out.println(s);
        }

3,泛型定义在接口上

    //泛型定义在接口上
    interface MyInter<T>{
        void access(T t);
    }

    //实现接口指定泛型
    class MyImpl1 implements MyInter<String>{
        @Override
        public void access(String t) {

        }
    }

    //实现接口后不知道传递什么类型
    class MyImpl2<T> implements MyInter<T>{
        @Override
        public void access(T t) {

        }
    }

发表评论

邮箱地址不会被公开。 必填项已用*标注

昵称 *