Java 泛型解析

Java 泛型解析

在Java中,泛型是通过<>来指定类型的一种方式,在没有泛型时候,我们将元素放入集合中的时候,会将所有的元素转化为Object类型,等到需要用的时候再拿出来将其转化为需要的类型,势必导致了代码的臃肿,例如下面的例子。

不对list进行类型的检查,我们可以将任意的Object类型存入list中,当我们需要使用到的时候需要对其进行转换,相当的麻烦。

List list=new ArrayList();
         list.add("123");
         list.add("234");
         list.add(2);

通过泛型来进行解决数组的类型的问题
List<String> list=new ArrayList();
list.add("123");
list.add("234");
list.add(2);

同样的,当我们在List通过中指定了具体的存入类型过后,我们就可以仅仅存入String,同时不需要进行类型的转换,当我们试图将2添加入list中的时候,将会提示无法将Interger转换为String的问题,确保了代码的严谨和准确。

定义泛型接口,泛型类

我们在编写代码的过程中,可以通过自定义泛型接口,自定义泛型类,实现自定义的泛型。

如下代码所示

public interface TestOut<T>{   //一个泛型的接口
       void out(T info);
    }
    public class Test<T> implements TestOut<T>{    //一个泛型的类
        T info;
        public Test(T info){
            this.info=info;
        }

        @Override
        public void out(T info) {
            Log.e("Test",info+"");
        }
    }

这里简单的实现了一个泛型的类和接口,同时类通过实现接口实现了泛型接口的方法。
值得注意的是,如果上面的实现的接口没有进行泛型的实现,如下面所示

public class Test<T> implements TestOut

实现的out方法将会默认的变成Object方法,不会和T对应起来。

实现泛型的继承

public class TestTwo extends Test{

 `   public TestTwo(T info) {
        super(info);
    }
}`

值得注意的是,上面的代码是错误的范例,当我们通过继承的时候,必须对父类的泛型进行指定,不能不对其规定类型,如下的代码就是正确的。

public class TestTwo extends Test<String>{

        public TestTwo(String info) {
            super(info);
        }
    }

这里我们为其指定了String的类型,构造函数也可以很自然的找到了对应的泛型类型。

同时,我们也可以对其进行不指定类型,就像是在使用这个类一样,必须对其进行指定类型,如Test或者直接选择不对其进行指定,同样的如果不对其进行指定,将会显示Object类型。

如下所示

public class TestTwo extends Test{


        public TestTwo(Object info) {
            super(info);
        }
    }

考虑下面的例子

void Test(List<Object> list){
        for (Object o:list){
            Log.e("Test",o.toString());
        }
   }

需要传入的对象的引用是List,理论上说的话,List 类型的引用是可以传入的,因为String是Object的子类,但是当我们进行导入这样编写的时候,发现,编译更本通不过,同时爆出下面的错误

Test(java.util.List<java.lang.Object>) cannot be applied to(java.util.List<java.lang.String>)

也就是说List根本就不是List的父类,所以不能这样的转化。

那如果这个时候我们在不知道需要传入的泛型的类型的时候,怎么传入参数呢?
这个时候就需要用到类型通配符

类型通配符

类型通配符在java中是一个?来表示的,表示我们不知道当时需要传入的参数,这个时候如上的代码就可以改写如下。

void Test(List<> list){
        for (Object o:list){
            Log.e("Test",o.toString());
        }
   }

这个时候,我们发现当我们进行传入参数的时候就可以进行了,这个时候,不论什么样的参数传入,都会默认的成为Object。

类型通配符的上限和下限

当我们需要指定List<?>中泛型的类型的时候,可以通过List<? extends Object> List<? super Object>进行指定通配符的上限和下限。

 void Test(List<? extends Number> list){  //设定通配符的上限
        for (Number o:list){
            Log.e("Test",o.toString());
        }
   }
void Test(List<? super Number> list){
        for (Object o:list){
            Log.e("Test",o.toString());
        }
   }

值得注意的是,如果我们尝试像通过通配符实现的集合添加元素的时候,将会编译错误,因为他不知道这个集合的类型,无法对其进行添加元素,如下面的代码。

void Test(List<? extends Number> list){
       list.add(2);       
   }

那如果我们需要像泛型集合中添加元素的时候,应该怎么办?
这个时候就要用到泛型方法。

泛型方法

泛型方法的格修饰符
修饰符<T,S....> 返回值 函数名(形参){
方法体….
}

一个例子如下

public <T>void  Test(List<T>  list){

   }

值得注意的是,如果当我们仅仅只需要传入一个引用的时候,这个时候应该尽量使用类型通配符 ,当我们的传入的引用与方法中的其他引用有着关系的时候,我们尽量使用泛型方法

猜你喜欢

转载自blog.csdn.net/zxc641483573/article/details/79089716