《effective java》item 28, 29,30

item 28 倾向于使用list而不是Array

  • 泛型和数组的区别(比如:List<Integer>Integer []
    • 数组是covariant的, 泛型不是。所谓covariant的意思是,子类数组的类型是父类数组类型的子类(Ingteger[]Object[]的子类,但List<Integer>不是List<Object>的子类)
    • 数组是具体化的,这意味着数组运行时完全知道类型信息,运行时给元素赋值其他类型数据,发生类型错误。
    • 而泛型的类型信息仅存在于编译期检查,但在运行时类型信息会被擦除。
    //编译通过,运行失败
    Object[] objectArray = new Long[1]; // 父类引用指向子类对象
    objectArray[0] = "I don't fit in"; 
    
    //编译失败
    List<Object> ol = new ArrayList<Long>(); //类型错误,因为ArrayList<Long>不是List<Object>的子类
    
  • 泛型与数组不能很好地融合。无法创建一个泛型数组,如new List<Integer>[]等是不合法的。
  • 可以声明泛型数组,但可能会造成错误,因此会有warning。使用List取代会更好。例子如下:
// Chooser类的作用是:给一个collection,随机取出其中一个元素
public class TestGenericsCmpToArrays {
  public static void main(String[] args) {

      TestGenericsCmpToArrays testGenericsCmpToArrays = new TestGenericsCmpToArrays();
      Collection<Integer> collection = Arrays.asList(1,2);
      int choose1 = (int) testGenericsCmpToArrays.new Chooser(collection).choose(); //无泛型,需要自己转换

      Collection<String> collection2 = Arrays.asList("1","2");
      String choose2 = testGenericsCmpToArrays.new Chooser2<>(collection2).choose();  //使用泛型,无须手动转换,但由于T[]而存在warning

      Collection<String> collection3 = Arrays.asList("1","2");
      String choose3 = testGenericsCmpToArrays.new Chooser3<>(collection3).choose(); // T[]转为List<T>,去除warning

  }

  class Chooser { //无泛型
      Object[] chooseArray;

      public Chooser(Collection<Integer> coll) {
          this.chooseArray = coll.toArray();
      }

      public Object choose() {
          ThreadLocalRandom current = ThreadLocalRandom.current();
          return  chooseArray[current.nextInt(chooseArray.length)];
      }
  }

  class Chooser2<T> { //声明了泛型数组
      T[] chooseArray;

      public Chooser2(Collection<T> coll) {
          this.chooseArray = (T[])coll.toArray();
      }

      public T choose() {
          ThreadLocalRandom current = ThreadLocalRandom.current();
          return  chooseArray[current.nextInt(chooseArray.length)];
      }
  }

  class Chooser3<T> { //使用List代替数组
      List<T> chooseArray;

      public Chooser3(Collection<T> collection) {
          this.chooseArray = new ArrayList<>(collection);
      }

      public T choose() {
          ThreadLocalRandom current = ThreadLocalRandom.current();
          return  chooseArray.get(current.nextInt(chooseArray.size()));
      }
  }

item 29: 倾向于使用泛型类型

  • 使用泛型类型的Stack示例
class ArrayStackGenerics<E>{
    private final  int CAP = 16;  //初始容量
    private int capacity = 0; //当前容量, 也是插入元素的位置(即栈顶+1)
    private E[] elements;

    public ArrayStackGenerics() {
        elements = (E[]) new Object[CAP];
    }

    public int getSize() {
        return capacity;
    }

    public boolean isEmpty() {
        return capacity == 0;
    }

    public E top() {
        return elements[capacity-1];
    }

    public void push(E e) {
        ensureCapcity();
        elements[capacity++] = e;
    }

    public E pop() {
        E result = elements[--capacity];
        elements[capacity] = null; //把当前引用,即上一个栈顶元素引用置为null
        return result;
    }

    public void ensureCapcity() {
        if (elements.length == getSize()) {
            elements = Arrays.copyOf(elements, getSize()*2 +1);
        }
    }
}

item 30: 倾向于使用泛型函数

public class TestGenericMethods_30 {

    public static void main(String[] args) {
        //
        Set<String> s1 = new HashSet<>();
        Set<String> s2 = new HashSet<>();
        s1.add("a"); s2.add("b");
        System.out.println(union(s1,s2));

        // identity()的作用是接受一个对象,返回该对象本身。
        // 使用泛型后的好处是,不需要为每一类的对象写一个方法。可以将UnaryOperator的类型设置Object,但这样作将输入参数的类型均向上转型为了Object
        String[] strs = new String[]{"ab","c"};
        UnaryOperator<String> sameString = identity();
        for (String s: strs)
            System.out.println(sameString.apply(s));

        Integer[] ints = new Integer[]{1,2};
        UnaryOperator<Integer> sameInteger = identity();
        for (int i: ints)
            System.out.println(sameInteger.apply(i));

        //recursive type bound
        List<Integer> list = Arrays.asList(1, 2, 3);
        System.out.println("max of (1, 2, 3) = "+max(list));
        List<String> stringList = Arrays.asList("a", "b", "z");
        System.out.println("max of (a, b, z) = " + max(stringList));
    }

    public static <T> Set<T> union(Set<T> s1, Set<T> s2) {
        Set<T> s = new HashSet<>(s1);
        s.addAll(s2);
        return s;
    }

    private static UnaryOperator<Object> IDENTITY_FUNC = (t)-> {return t;};
    @SuppressWarnings("unchecked")
    public static <T>  UnaryOperator<T> identity() {
        return (UnaryOperator<T>) IDENTITY_FUNC;
    }

    // 限制了E必须是实现了对应类型的Comparable接口
    public static <E extends Comparable<E>> E max(Collection<E> c) {
        E res = null;
        for (E r: c) {
            if (res == null) {
                res =  r;
                continue;
            }
            if (r.compareTo(res)>0)
                res = r;
        }
        return res;

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值