持有对象(也就是把对象存储到容器中得以持有)

持有对象听起来好像有点高大上,其实也就是把对象存储到容器中得以持有,而这个容器就是我们常说的集合类。

其实本章中大篇幅只是再教你如何使用这些集合类,具体到一些方法上并去使用这些,这里我就不做演示,只是把其中的一些特殊的例子,用法以及我自己感觉比较重要但是有可能大家都不一定会很清楚的地方在这里总结出来。后面会有容器的深入研究,这里只是把区别用法罗列。

由这张图,我们先有一小的总结:

1.Collection是一个独立元素的序列。而List、Set、Queue都是其实现,只是各自的规则不一样。

2.Map。一组成对的“键值对”(key=value)对象。

 

下面先对Collection以及由此延伸的接口或者是实现类做一个常用的总结。

而我们通常在代码中调用时,通常会List<> list = new ArrayList/LinkedList<>()

当然我们也可以不使用这种向上转型的方式,但是面向接口编程可以使得我们的代码重构能够更有优化。假设在程序设计初期,可能List<> list = new ArrayList<>()使用,但是在某个时候我需要在这块大量进行插入删除,这个时候我只需要把List<> list = new LinkedList<>()进行修改,因为各自都是向上转型List的对象,在原先代码上就不需要修改,这就是一个好处。但是当你确定了此处代码上只会使用到随机访问,这个时候可使用ArrayList list = new ArrayList<>()进行创建,这样做可以使得我们能够更多的使用到ArrayList的方法。同样的道理在Set,Map中也是一样的。

List:ArrayList和LinkedList(用法上就不多说了,常用就那几个)

这里比较特殊的地方:我们通常可以使用工具类Array.asList来把一个数组转换到容器中,但是因为这个方法的底层,还是把这个输出当成一个数组,所以当我们需要add()或者是delete(),会报错。并且

A 
B extend A
C extend B

当List<A> list = Ararry.asList(C) 虽然C也是A的导出类,但是这样编译器会报错,因为使用asList只能判断C类型,List<C>是可以通过,这说明这个方法没有进行类型检查,但是我们可以使用List<A> list = Ararry.<A>asList(C)显式类型参数说明。

Set:HashSet、TreeSet和LinkedHashSet

其中TreeSet在创建时因为是进行排序,在构造时可以传入排序类型。如 Set<String> words = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);根据字母顺序排序。

Map:HashMap、TreeMap和LinkedHashMap(各自的特性也是跟Set差不多,当你看源码时会发现,其实Map就是使用Set构造)

Queue(队列FIFO先进先出)可以想象成管道:PriorityQueue、Queue

由图我们可以看到LinkedList实现了Queue接口,那么我们可以使用向上转型:Queue<T> queue = new LinkedList<T>()进行创建。而PriorityQueue是一种可以实现优先级的队列,

stringPQ = new PriorityQueue<String>(
  strings.size(), Collections.reverseOrder());

传入的Collections.reverseOrder()是反序的Comparator。

 

在这里着重看一下迭代器(也是一种设计模式)。首先我们需要了解的是迭代器的思想:容器必须是要有确切的类型。而当我们编写一些通用的代码,也是需要在这个确切的类型上进行编写。当我们更换比如List换成Set,这个确切类型发生了变化,这个时候我们的通用代码是不是可能会出现一些不兼容的问题,这样我们需要再一次去编写通用代码。这种关系到了确切类型上的代码,使得代码上多余了重写的部分的可能。而这个时候我们就可以引用迭代器,迭代器是一个对象,而它可以去遍历选择序列的对象,举个例子:我本身是一个迭代器对象,而我有一个钱包,钱包里面装着硬币,纸币,由我这个迭代器去看钱包里面这些东西,不用关心这里面是硬币类型还是纸币类型,我这个迭代器只需要把硬币纸币拿出来就行了。而这个就是迭代器的思想。

一、其中Iterator只支持单向向前(用法)

二、ListIterator可以双向,并可以指定到某一位置开始的索引。其他用法更加全面,这里就不详细介绍,编程思想更在于思想而不是用法。

既然这样,当我们需要去进行编写一个序列通用工具,,如下:

public static void display(Iterator<Pet> it) {
  while(it.hasNext()) {
    Pet p = it.next();
    System.out.print(p.id() + ":" + p + " ");
  }
  System.out.println();
}
public static void display(Collection<Pet> pets) {
  for(Pet p : pets)
    System.out.print(p.id() + ":" + p + " ");
  System.out.println();
}  

我们可以看到一个是直接使用了Collection(“描述所有序列容器的共性接口”),因为Collection实现了Iterable接口,属于其类型,所以我们可以使用foreach语法,等会说。那如果我们需要在Collection的基础上新添加一些自用的序列类型,并传入上面display方法中,那么我们要么实现Collection接口,要么去创建一个Iterator,这两种的差别:假设我只是想去使用这个通用类,实现接口需要把Collection的所有方法重写,这样就显得多余,但是需要仅仅去创建一个Iterator就简单多了:

public Iterator<Pet> iterator() {
  return new Iterator<Pet>() {
    private int index = 0;
    public boolean hasNext() {
      return index < pets.length;
    }
    public Pet next() { return pets[index++]; }
    public void remove() { // Not implemented
      throw new UnsupportedOperationException();
    }
  };
这时候就体现了Iterator的好处。

foreach与迭代器

foreach语法主要用于数组,但是能够作用于序列主要是JAVA SE5之后提供的新特性。,下面是实现Iterable接口的一个例子(foreach语法通过实现Iterator进行移动):

public class IterableClass implements Iterable<String> {
  protected String[] words = ("And that is how " +
    "we know the Earth to be banana-shaped.").split(" ");
  public Iterator<String> iterator() {
    return new Iterator<String>() {
      private int index = 0;
      public boolean hasNext() {
        return index < words.length;
      }
      public String next() { return words[index++]; }
      public void remove() { // Not implemented
        throw new UnsupportedOperationException();
      }
    };
  }	
  public static void main(String[] args) {
    for(String s : new IterableClass())
      System.out.print(s + " ");
  }
}

ps:foreach可以用做数组或者是Iterable类型,但是“不代表数组就是Iterable,任何自动包装也不会发生”

public class ArrayIsNotIterable {
  static <T> void test(Iterable<T> ib) {
    for(T t : ib)
      System.out.print(t + " ");
  }
  public static void main(String[] args) {
    test(Arrays.asList(1, 2, 3));
    String[] strings = { "A", "B", "C" };
    // An array works in foreach, but it's not Iterable:
    //! test(strings);
    // You must explicitly convert it to an Iterable:
    test(Arrays.asList(strings));
  }
}

   test(strings);没办法自动转换,需要我们手动 test(Arrays.asList(strings));才能编译通过。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值