【Java基础】泛型的一些总结

什么是泛型

泛型其实可以理解为一种广泛的类型,啥类型都型,当然,这种泛是指定义时可以广泛,但是使用时必须确定类型。也就是说,当不清楚未来使用哪种类型时,定义为泛型。可以支持泛型类,泛型接口,泛型方法,泛型成员变量。

泛型的好处

  1. 泛型可以将类型作为参数进行传递,即类型可以像参数一样实现参数化。 
  2. 泛型能提高代码的重用。
  3. 在编译的时候检查类型安全,把运行期的问题提前展现出来。
  4. 泛型中的强制转换都是自动和隐式的 

下面用几个示例来表明这几种好处:

下面的代码表示的是代码重用的案例,几个传入不同类型的a都可以用泛型T表示。

    public void show(int a){
        System.out.println(a);
    }

    public void show(Boolean a){
        System.out.println(a);
    }
    public void show(String a){
        System.out.println(a);
    }

    public void show(T a){
        System.out.println(a);
    }

下面这段代码在编译期间是不会出错的,因为集合中可以传入任何对象,但是一运行就会出错,因为后面遍历时进行强制转换为Integer,String是不能强转为Integer的。

        List s = new ArrayList();
        s.add(1);
        s.add(2);
        s.add("hello");
        Iterator it = s.iterator();
        int sum = 0;
        while (it.hasNext()){
            Integer i = (Integer) it.next();
            sum += i;
        }

但是由于ArrayList是泛型类,如果在定义的时候提前确定将来要存储在List中的类型,则可以提前提示出错误,这个就类似我们定义数组,刚开始就确定了数组的类型。

自动强制用的最多的地方就是在Iterator时规定了迭代的类型,所以在遍历时不用做强转工作,会自动强转。

        List<Integer> s = new ArrayList();

        s.add(1);
        s.add(2);
//        s.add("hello");
        Iterator<Integer> it = s.iterator();
        int sum = 0;
        while (it.hasNext()){
//            Integer i = (Integer) it.next();
            sum += it.next();//由于Integer中规定了类型,这里会自动强制转换
        }

泛型类(Object和泛型类的区别--思考引入泛型的原因)

Object也可以代替任何类型,那Object是否可以取代泛型呢?接下来看一个示例程序:

public class Test {
    public static void main(String[] args) {
        Animal animal = new Animal();
        animal.setAttr(3);
        Integer age = (Integer) animal.getAttr();
        System.out.println(age);

        System.out.println("---------------------");
        animal.setAttr("dog");
        String kind = (String) animal.getAttr();
        System.out.println(kind);

        System.out.println("---------------------");
        animal.setAttr("kity");
        Integer name = (Integer) animal.getAttr();//不按常规出牌,编译不报错
        System.out.println(name);

    }
}

class Animal {
    private Object attr;

    public Animal() {
    }

    public Object getAttr() {
        return attr;
    }

    public void setAttr(Object attr) {
        this.attr = attr;
    }
}

  明显Test中最后一段设置姓名是String,但是做强转可能没搞清楚,偏偏转到Integer了,但是这个时候是不会报错的,因为编译期间Object是可以向子类Integer向下转型的。但是运行时就会报错,所以利用Object来写这种程序是不安全的。但是如果将Object替换为泛型,则会在编译期间就会报错。

  上述代码,如果将Animal定义为泛型类,即将Object都替换为泛型支持,并在Animal后面加上尖括号<T>,于此同时保持测试代码不变,依然编译期间不会报错,这说明,如果不指定T的类型,默认应该还是将T换成了Object。

  但是,泛型类的使用规则是需要你定义的时候就规定将来的类型的,在定义时讲T确定为Integer后,上述代码有三行编译出错。

public class Test {
    public static void main(String[] args) {
        Animal<Integer> animal = new Animal<>();
        animal.setAttr(3);
        Integer age = (Integer) animal.getAttr();
        System.out.println(age);

        System.out.println("---------------------");
        animal.setAttr("dog");//编译不通过
        String kind = (String) animal.getAttr();//编译不通过
        System.out.println(kind);

        System.out.println("---------------------");
        animal.setAttr("kity");//编译不通过
        Integer name = (Integer) animal.getAttr();
        System.out.println(name);

    }
}

class Animal<T> {
    private T attr;

    public Animal() {
    }

    public T getAttr() {
        return attr;
    }

    public void setAttr(T attr) {
        this.attr = attr;
    }
}

泛型方法

  泛型类有一个特点,就是需要在实例化类的时候明确泛型的类型,不然有警告(不然就是当作Object),一旦定义了,接下来类中的所有泛型的T都确定了。也就是说如果实例化的时候将T定义为String,则类中所有的T都是String,这样不是太灵活。所以引入了泛型方法。

  泛型方法的定义特征:public static <T> List<T> asList(T... a)

     这里用Arrays中的asList方法来举例说明,泛型方法是将以前泛型类中的<T>放到了方法返回值前面。这样asList方法以后可以接受任何类型的传参了。

     ps:这篇文章对泛型方法进行了更深入的总结http://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html

泛型接口

泛型接口和泛型类类似,只是实现泛型接口的类一般也是继续泛型下去,如若不然,则泛型接口的灵活性就没有被突显了。

public interface Animal<T> {
    public abstract void show(T a);
}
public class Dog<T> implements Animal<T>{

    @Override
    public void show(T a) {
        System.out.println(a);
    }
}

泛型的高级运用-通配符


 1. ?:            任意类型,如果没有明确,那么就是Object以及任意的Java类了
 2. ? extends E:  向下限定,E及其子类
 3. ? super E:    向上限定,E极其父类
 
public class GenericDemo {
    public static void main(String[] args) {
        // 泛型如果明确的写的时候,前后必须一致
        Collection<Object> c1 = new ArrayList<Object>();
        // Collection<Object> c2 = new ArrayList<Animal>();
        // Collection<Object> c3 = new ArrayList<Dog>();
        // Collection<Object> c4 = new ArrayList<Cat>();

        // ?表示任意的类型都是可以的
        Collection<?> c5 = new ArrayList<Object>();
        Collection<?> c6 = new ArrayList<Animal>();
        Collection<?> c7 = new ArrayList<Dog>();
        Collection<?> c8 = new ArrayList<Cat>();

        // ? extends E:向下限定,E及其子类
        // Collection<? extends Animal> c9 = new ArrayList<Object>();
        Collection<? extends Animal> c10 = new ArrayList<Animal>();
        Collection<? extends Animal> c11 = new ArrayList<Dog>();
        Collection<? extends Animal> c12 = new ArrayList<Cat>();

        // ? super E:向上限定,E极其父类
        Collection<? super Animal> c13 = new ArrayList<Object>();
        Collection<? super Animal> c14 = new ArrayList<Animal>();
        // Collection<? super Animal> c15 = new ArrayList<Dog>();
        // Collection<? super Animal> c16 = new ArrayList<Cat>();
    }
}

class Animal {
}

class Dog extends Animal {
}

class Cat extends Animal {
}
原文地址:https://www.cnblogs.com/gslyyq/p/4970286.html