《effective java》item 31, 32

item 31: 使用通配限定符提高api灵活性

  • 更符合逻辑。
    假设有一个Stack<Number>, 其中的push定义如下

     public void push(E e) {
        ensureCapcity(); //确保容量足够,不够扩容。
        elements[capacity++] = e;
    }
    

    那么,stack.push(new Integer(1))是可以的。因为Integer是Number的子类

    现在定义一个pushAll方法

    public void pushAll(Collection<E> coll) {
        for (E e: coll) {
            push(e);
        }
    

    使用 stack.pushAll(Array.asList(1,2,3))则无法通过编译。因为Collection<Interger>不是Collection<Number>的子类。

    如此一来,push可以传一个整数,但pushAll却无法传一个整数集合,略显奇怪。

    加入通配符?可解决这个问题

    public void pushAll(Collection<? extends E> coll) {
        for (E e: coll) {
            push(e);
        }
    

    同理,创建一个popAll, 传入一个集合,接收所有pop的元素

    public void popAll(Collection<? super E> pops) {
        while (!isEmpty()) pops.add(pop());
    }
    

    Collection<? super E> pops 的好处是,pops类型可以是Stack元素类型的父类。比如,pops = new ArrayList<Object>。将pops传入 stack.popAll(pops), 可将stack的所有元素(Number类型)pop出来,转换为Object类型放到pops中

  • 生产使用<? extends E?> , 消费使用<? super E>

  • 不要在返回值处使用限定通配符

item 32: 小心地结合泛型和可变长参数

  • 可变长参数底层是一个数组,加上泛型后,方法内部往数组添加元素是不安全的。会有warning
  • 但可变长参数只是用来接收参数,一般不会往里面添加元素。因此,在不添加元素且确定函数内部的类型安全后,添加@SafeVarargs去除warning
  • 让其他方法访问 可变长参数形成的数组,这是不安全的。 例子:
    static <T> T[] toArray(T... args) {
        return args;    //返回参数数组
    }

    static <T> T[] pickTwo(T a, T b, T c) { //此方法访问了可变长参数形成的数组,其目的是从参数中随机选两个。
        switch(ThreadLocalRandom.current().nextInt(3)) {
            case 0: return toArray(a, b);
            case 1: return toArray(a, c);
            case 2: return toArray(b, c);
        }
    }

    public static void main(String[] args) {
        // 类型转化Exception
        // 因为存在泛型擦除,pickTwo返回的实际上是Object[], 无法转化String[]
        String[] attributes = pickTwo("Good", "Fast", "Cheap"); 
    }
  • 安全的做法
    static <T> List<T> pickTwoSafe(T a, T b, T c) {
        switch(ThreadLocalRandom.current().nextInt(3)) {
            case 0: return toArraySafe(a, b);
            case 1: return toArraySafe(a, c);
            case 2: return toArraySafe(b, c);
        }
        throw new AssertionError(); // Can't get here
    }

    @SafeVarargs
    static <T> List<T> toArraySafe(T... args) {  // 返回值类型List<T> 而不是 T[]
        List<T> res = new ArrayList<>();
        for (T arg : args) res.add(arg);
        return res;
    }

    public static void main(String[] args) {
       
        List<String> attributes =  pickTwoSafe("a", "b", "c");
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值