持有对象——容器类

分类

Java的容器类分为Collection和Map两种类型
Collection:描述了一个集合的概念,根据不同的需求又提供了不同的实现。List 集合必须按照插入的顺序保存对象;Set集合中不能有重复元素;Queue集合按照 队列的规则进行元素操作。
Map:map中保存的是“键值对”对象,它允许使用者通过对象(键)来查找对象(值)。

Collection

  1. 添加元素
Collection<Integer> collection = new ArrayList<>();   //传统创建方式
Collections.addAll(collection,1,2,3,4,5);  //为collection对象添加元素,理论上要快一点
collection.addAll(Arrays.asList(6,7,8,9,10));         //为collection对象添加元素
List<Integer> list = Arrays.asList(1, 2, 3, 4, 5);     //接受可变参数,然后返回一个AbstractList类型的对象
//list.add(6); //运行时会报错,因为AbstractList对底层数组没有提供扩展机制

值得一提的是Arrays.asList()方法对所保存的对象的类型做出最理想的假设,即以你传进去的参数的类型为准,例如:

Arrays.asList(1,2,3,4,5);  //那保存的对象类型就是Integer
List<Fruit> fruits = Arrays.asList(new Orange(), new Apple());  //这时会保存为其父类的类型
//Arrays.<String>asList(1);           //可以在asList方法前加<>指定容器的类型,此时在向容器中添加其他类型就会在编译时报错
 //List<String> l = Arrays.asList(1, 2, 3, 4);  //返回的容器类型为Integer类型,却把他保存在String类型容器声明的变量中会在编译时报错
  1. List
    List提供了保存所有数据对象的功能,提供了比Collection接口更多的操作。他的实现类包括ArraysList和LinkedList。两者的不同之处在于ArraysList使用数组(顺序表)作为底层所以适合随机存取。但是不利于删除和插入操作(因为极可能会涉及大量数据的移动);而LinkedList使用双向链表作为底层极大的方便了插入和删除操作,但不方便随机存取(必须从第一个元素开始挨个比较,直到找到要找的元素)。
    LinkedList
    除了底层的实现方式的差别外,LinkedList还比ArrayList提供了更多的方法,实现了栈、队列、双端队列等的数据结构(当然栈和队列其实Java有单独的实现)。
    下面我们就用LinkedList的方法来实现一个我们自定义的栈结构
class Stack<E> {
        private LinkedList<E> storage = new LinkedList<>();

        public void push(E e) {
            storage.push(e);
        }
        public E top() {
            return storage.getFirst();
        }
        public E pop() {
            return storage.pop();
        }
        public boolean isEmpty() {
            return storage.isEmpty();
        }
    }

对于栈推荐使用LinkedList来实现而避免使用Java提供的Stack。因为Stack的底层是使用数组来实现的,在压入元素或者弹出元素时会涉及到数组的扩张或者收缩。
2. Iterator
Iterator
Iterator仅能单向移动,只能使用四个方法:
a. iterator(),获取一个Iterator对象,该对象将会准备好该列表中的第一个数据元素
b. hasNext() 判断列表中是不是还有未取出的元素
c. next() 取出下一个元素
d. remove() 删除上一次取出的元素(这意味着在我们使用remove方法之前必须先使用next方法)
ListIterator
ListIterator是一个专门针对List容器的一个迭代器,与Iterator的不同之处在于:a.
a. ListIterator支持双向移动
b. 可以使用nextIndex()和previousIndex()方法获取当前指针指向的元素的索引和上一元素的索引
c. 可以使用set()方法替换掉上一次取出的元素的值。

  1. Set
    Set集合的特点是不保存重复元素,所以我们经常使用Set来判断元素的归属问题。HashSet、TreeSet和LinkedHashSet是Set的三个重要实现。
    HashSet采用了散列的方式存储存数据,所以存储的数据是无序的方便快速查找。
    TreeSet采用红-黑树结构来存储数据,默认按照升序排序。
    LinkedHashSet按照插入的顺序保存数据的同时也保证了一定的查询的效率。

  2. Map
    Map保存的对象是键值对,允许我们建立对象用于对象之间的映射,方便使用对象来查找对象。

  3. Queue
    LinkedList实现了Queue接口,所以LinkedList可以直接向上转型使用Queue的方法。
    PriorityQueue
    PriortyQueue是一个优先级队列,也就是说他建立队列的方法是按照优先级规则来建立的,并不是谁先来谁就在第一个的位置。默认是按照自然序建立队列,如果想按照其他顺序则需要在构造方法中传入Comparator(比较器)。

  4. Foreach与迭代器
    我们在使用数组和Collectioin对象的时候都用过foreach(增强for循环)来遍历每一个元素。但是你知道为什么他们能够被Foreach语句遍历吗?因为他们实现了Iterable接口(数组没有实现)。只要实现了Iterable接口那么我们所创建的类的对象也可以使用Foreach语句来遍历。例如:

package test;


import javax.swing.*;
import java.io.Serializable;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        TestIterable t = new TestIterable();
        for (String s : t) {
            System.out.println(s);
        }

    }
    static class TestIterable implements Iterable<String> {
        private String[] s = "to be or not to be".split(" ");
        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {
                private int i = 0;
                @Override
                public boolean hasNext() {
                    return i < s.length ? true : false;
                }

                @Override
                public String next() {
                    return s[i ++];
                }
            };
        }
    }
}

这时我们已经可以使用Foreach语句来遍历TestIterable类的对象了,可是如果我们现在除了要正序遍历这个对象外还想逆序遍历甚至乱序遍历,这时该怎么办呢?毫无疑问继承是完全可以的,我们可以再写一个这个类的子类,然后重写他的Iterator方法就行了。但是除此之外是不是还有更好的方法呢?我们发现foreach语句能够便利的关键在于Iterable接口,所以只要满足这个接口就行,这样一来我们就可以写一个方法来返回一个Iterable接口的实现就好了。这种已经有了一个接口但是还需要另外的接口的状况就叫适配器模式。新的接口的实现就是适配器。

package test;


import javax.swing.*;
import java.io.Serializable;
import java.util.*;

public class Test {
    public static void main(String[] args) {
        TestIterable t = new TestIterable();
        for (String s : t) {
            System.out.println(s);
        }
        for(String s : t.reverse()) {
            System.out.println(s);
        }
        for (String s : t.random()) {
            System.out.println(s);
        }

    }
    static class TestIterable implements Iterable<String> {
        private String[] s = "to be or not to be".split(" ");
        @Override
        public Iterator<String> iterator() {
            return new Iterator<String>() {
                private int i = 0;
                @Override
                public boolean hasNext() {
                    return i < s.length ? true : false;
                }

                @Override
                public String next() {
                    return s[i ++];
                }
            };
        }
        public Iterable<String> reverse() {
            return new Iterable<String>() {
                @Override
                public Iterator<String> iterator() {
                    return new Iterator<String>() {
                        private int i = s.length - 1;
                        @Override
                        public boolean hasNext() {
                            return i >= 0 ? true : false;
                        }

                        @Override
                        public String next() {
                            return s[i --];
                        }
                    };
                }
            };
        }
        public Iterable<String> random() {
            return new Iterable<String>() {
                @Override
                public Iterator<String> iterator() {
                    List<String> list = new ArrayList<>(Arrays.asList(s));//将Arrays.asList(s)的结果又创建了一个新的ArrayList对象保存,如果直接在返回结果上进行洗牌则会导致s数组的顺序也被打乱
                    Collections.shuffle(list,new Random(12));
                    return list.iterator();
                }
            };
        }
    }
}

发布了57 篇原创文章 · 获赞 55 · 访问量 1945

猜你喜欢

转载自blog.csdn.net/qq_40561126/article/details/104315620
今日推荐