第15章 泛型

  1. 具有private构造器的类在该类外部不能new对象,也不能在外部被继承。
  2. 内部类中使用"外部类类名.this"表示外部类的this。
  3. 对于一个static方法而言,无法访问泛型类的类型参数:
class GenericSetter<T> {
    // 编译错误,static方法无法访问泛型类的类型参数:
    static void set(T arg) {
        System.out.println("GenericSetter");
    }
}

如果static方法想要使用泛型能力,就必须使之成为泛型方法。定义泛型方法只需将泛型参数列表置于返回值之前:

class GenericSetter<T> {
    // 定义泛型方法:
    static <E> void set(E arg) {
        System.out.println("GenericSetter");
    }
}
  1. 只有当你希望使用的类型参数比某个具体类型(以及它的所有子类型)更加泛化时——也就是说,当你希望代码能够跨多个类工作时,才有必要使用泛型,否则可以用多态代替。
  2. 泛型支持多重边界:
    < T extends 类名 & 接口名 & 接口名 >
    类在前,接口在后,接口可有多个,类只能一个。
  3. 将子类数组向上转型为父类数组,并向数组中添加父类对象,该行为在编译期不会报错,但运行时会触发异常:
    public static void main(String[] args) {
        Fruit[] fruits;
        Apple[] apples = new Apple[10];
        fruits = apples; // 向上转型
        // 编译通过,但运行时引发异常:java.lang.ArrayStoreException
        fruits[0] = new Fruit();
    }

使用泛型容器来代替数组,可以将这种错误检测移入编译期,因为泛型容器不支持这种向上转型:

    public static void test01() {
        List<Fruit> fruits;
        List<Apple> apples = new ArrayList<>();
        // 编译不通过!
        fruits = apples;
    } 

Apple是Fruit,但Apple的List不是Fruit的List!
但是,有时你确实想在这两个类型之间建立某种向上转型的关系,这时可以使用通配符:

    public static void test01() {
        List<? extends Fruit> fruits;
        List<Apple> apples = new ArrayList<>();
        // 编译通过!
        fruits = apples;
        // 但是不能往转型后的List添加任何数据,除了null(这没有任何意义)
        //! fruits.add(new Object());
        //! fruits.add(new Apple());
        //! fruits.add(new Fruit());
        fruits.add(null);
    } 
}

不能添加任何数据的原因是:向上转型后的fruits可能是Apple类型的List,也有可能是Apple子类的List,甚至是Apple子类的子类的List,即你不能保证<? extends Fruit>的下界在哪里,因此往其中添加任何对象都有可能造成类型不匹配,而编译器必须规避这种错误,所以。
然而,这并不意味着向上转型已经无计可施,我们还可以走另外一条路,即使用超类型通配符:

    public static void test01() {
        // <? super Apple>表示Apple或者Apple的父类。
        List<? super Apple> supApples;
        List<Fruit> fruits = new ArrayList<>();
        // 编译通过!
        supApples = fruits;
        // 只能添加Apple或者Apple的子类!
        supApples.add(new Apple());
        supApples.add(new RedApple());
        // 即便它实际上是一个Fruit的List,但是不能往其中添加Fruit对象
        //! supApples.add(new Fruit());
    }
<? super Apple>保证了List的下界,因为无论进行怎样的向上转型,supApples都会支持Apple和Apple的子类型,因此向supApples中添加Apple或Apple的子类型是安全的。
  1. 无界通配符<?>意味着任何事物,表示将持有某种具体类型的同构集合。它与不使用泛型时的情况不同,不使用泛型表示任何类型,而<?>表示类型是具体的,只是我现在还不知道它是什么样的类型。
  2. 不能使用基本类型作为类型参数,不能创建形如ArrayList< int >之类的东西。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值