Java泛型

  |   0 评论   |   0 浏览

Java泛型

https://www.cnblogs.com/ooo0/p/7569595.html

泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

泛型的好处是在编译的时候检查 类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。

泛型类、泛型接口、泛型方法

规则限制

  1. 泛型的类型参数只能是 类类型(包括自定义类),不能是简单类型
  2. 用一种类型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
  3. 泛型的类型参数可以有多个
  4. 泛型的参数类型可以使用extends语句,例如< T extends superclass > 。习惯上称为“游有界类型”。
  5. 泛型的参数类型还可以是 通配符类型。例如:Class<?> classType = Class.forName(java.lang.String"");p
public class MyTest {

    static class Gen <T> {
        private T ob;

        public void setOb(T ob) {
            this.ob = ob;
        }

        public T getOb() {
            return ob;
        }
        public void showType () {
            System.out.println("T的实际类型:" + ob.getClass().getName());
        }
    }

    public static void main(String[] args) {
        Gen<String> gen = new Gen<String>();
        gen.setOb("asd");
        gen.showType();
        Gen<List<String>> listGen = new Gen<>();
        listGen.setOb(Arrays.asList("1", "2"));
        listGen.showType();
    }
}

T的实际类型:java.lang.String
T的实际类型:java.util.Arrays$ArrayList

限制泛型

上面例子中,由于没有限制class Gen<T> 类型持有者T的范围,实际上这里限定类型相当于Object,这和“Object泛型”实质上是一样的。限制比如我们要限制为T为集合接口类型。可以这样做:

class Gen< T extends Collection> 这样类中的泛型T只能是 Collection接口的 实现类,传入 非Collection接口 编译 就会报错。

注意:<T extends Collection > 这里的限定使用关键字 extends,后面可以是类也可以是接口,但这里的 extends 已经不是继承的含义了,应该理解为T类型 实现 Collection接口的类型,或者 T 是继承了 XX类的类型。

public class MyTest {

    static class Gen <T extends Collection<?>> {
        private T ob;

        public void setOb(T ob) {
            this.ob = ob;
        }

        public T getOb() {
            return ob;
        }
        public void showType () {
            System.out.println("T的实际类型:" + ob.getClass().getName());
        }
    }

    public static void main(String[] args) {
        Gen<List<String>> arrayListGen = new Gen<>();
        arrayListGen.setOb(Arrays.asList("213", "asd"));
        arrayListGen.showType();
    }
}

T的实际类型:java.util.Arrays$ArrayList

多接口限制

虽然Java泛型简单的用extends统一表示了原有的extends和implements概念,但仍要遵循应用的体系,Java只能继承一个类,但可以实现多个接口,所以你的某个类型需要用extends限定,且有多种类型的时候,只能存在一个是类,并且类写在第一位,接口列在后面,也就是:

< T extends SomeClass & interface1 & interface2 & interface3 >

public class Demo < T extends Comparable & Serializable > {
  // T 类型 就可以用Comparable 声明的方法和 Serializable 所拥有的特性了。
}

通配符泛型

为了解决类型被限制死了,不能动态根据实例来确定的缺点,引入了 “通配符泛型”。针对上面的例子,使用通配泛型格式为< ? extends Collection > ,?代表位置类型,这个类型是实现Collection接口。

注意:

  1. 如果只指定了< ? > ,而没有extends ,则默认是允许Object及其下的任何Java类了。也就是任意类。
  2. 通配符泛型不单可以向上限制,如< ? extends Collection >, 还可以向下限制,如 < ? super Double > ,表示类型只能接受Double 及其 上层父类类型,如 Number、Object类型的实例。
  3. 泛型类定义可以有多个泛型参数,中间用逗号隔开,还可以定义泛型接口、泛型方法。这些都与泛型方法中泛型的使用规则相似。

泛型方法

是否拥有泛型方法,与其所在的类是否有泛型没有关系。要定义泛型方法,只需将泛型参数列表置于返回值前。如:

public class MyTest {


    public static <T> void hello (T t) {
        System.out.println(t.getClass().getName());
    }

    public static void main(String[] args) {
        hello("asd");
        hello(123);
        hello(new String[]{"3", "2", "1"});
    }
}

java.lang.String
java.lang.Integer
[Ljava.lang.String;

使用泛型方法时,不必指明参数类型,编译器会自己找出具体的类型。泛型方法除了定义不同,调用就想普通方法一样。

需要注意,一个static方法,无法访问泛型类的类型参数,所以若要static方法需要使用泛型能力,必须使其成为泛型方法。

Java泛型的另一种说法 协变、逆变和不变

https://www.jianshu.com/p/90948ff4a940?utm_source=oschina-app

  • 协变:< ? extends T > 、逆变 < ? super T > 和不变 T