Java学习笔记--常用容器
阅读原文时间:2023年07月11日阅读:4

容器

解决程序运行时需要创建新对象,在程序运行前不知道运行的所需的对象数量甚至是类型的问题。

Java中提供了一套集合类来解决这些问题包括:List、Set、Queue、Map

  • Collection:独立的元素序列,都服从一条或多条的规则

  • Map:成对的“键对值”对象,允许使用键来查找值

3.1添加一组元素

Array.asList()方法:

该方法接受一个数组或用逗号隔开的元素列表,并转换为一个List对象。

Collection.addAll()方法:

接受一个Collection对象,可以使用Array.asList()产生Collection对象。

Collecions.addAll()方法:

接受一个Collection对象,以及数组或者逗号隔开的元素列表,并将元素添加到Collection对象中。

Collection()构造器方法:

Collection构造器方法接受一个Collection对象用于自身初始化。

public class TestAddObj {
    public static void main(String[] args) {
        Collection<Integer> collection = new ArrayList<>(Arrays.asList(1,2,3,4,8));// 构造器添加元素
        Integer[] moreInts = {7,5,6};
        collection.addAll(Arrays.asList(moreInts)); //Collection对象addAll()方法添加元素

        Collections.addAll(collection,9,10,11,12);//Collections类addAll方法添加元素
        Collections.addAll(collection,moreInts);//以Collection对象添加元素

        for (int i: collection) {
            System.out.print(i+"\t");//打印元素
        }

        List<Integer> list =  Arrays.asList(1,2,3,6); //直接使用Array.asList方法添加
//        list.add(3); // 报错,使用该方法产生的List本质上数组,不能修改大小,即不能适应add方法添加元素或delete方法删除元素
        list.set(2,10);

        System.out.println();
        for (int i: list) {
            System.out.print(i+"\t");
        }
    }
}

3.2 打印

使用打印默认的打印行为(容器提供的toString()方法

public class TestPrintContainers {
    public static void main(String[] args) {
        System.out.println(fill(new ArrayList<>()));
        System.out.println(fill(new LinkedList<>()));
        System.out.println(fill(new HashSet<>()));
        System.out.println(fill(new TreeSet<>()));
        System.out.println(fill(new LinkedHashSet<>()));
        System.out.println(fill(new TreeMap<>()));
        System.out.println(fill(new HashMap<>()));
        System.out.println(fill(new LinkedHashMap<>()));

    }
    static Collection<String> fill(Collection<String> collection){
        collection.addAll(Arrays.asList("rat","cat","dog"));//使用Collection对象作为参数添加一组元素
        return collection;
    }
    static Map<String,String> fill(Map<String,String> map){
        map.put("rat","Fuzzy");
        map.put("cat","Rags");//put<key,value>添加键值 get(key)获取键的值
        map.put("dog","Bosco");
        map.put("dog","Spot");
        return map;
    }
}

List接口在Collection接口的基础上添加了大量的方法,使得可以在List中间插入和移除元素

List接口的实现类

  • ArrayList

    长于随机访问元素,在其中插入和移除元素时较慢

  • LinkedList

    随机访问较慢,可以较低代价的在List中间插入和移除元素

    public class testList {
    public static void main(String[] args) {
    Random rand = new Random(100);
    ArrayList pets = Pets.namePets(7);// 产生pets

        System.out.println("1: "+pets);
        Pet lola = new Pet("lola");
    pets.add(lola);//add(obj) 列表最后插入obj
    System.out.println("2: "+pets);
    System.out.println("3: "+pets.contains(lola));// contains()判断是否包含
    pets.remove(lola); //remove(obj)删除列表中的对obj象
    Pet p = pets.get(2); //get(Index)获取索引位置对象
    System.out.println("4: "+p+" "+pets.indexOf(p));//indexOf(obj)获取obj对象的位置
    Pet milo = new Pet("Milo");
    pets.add(milo);
    System.out.println("5: "+ pets.indexOf(milo));
    System.out.println("6: "+ pets.remove(milo));
    
    System.out.println("7: "+pets.remove(p));
    System.out.println("8: "+pets);
    
    pets.add(3,new Pet("Jack"));//add(index,obj)将obj插入到index位置
    System.out.println("9: "+pets);
    
    List&lt;Pet&gt; sub = pets.subList(1,4);//sub(start,end)获取[start,end)列表片段
    System.out.println("10: sub list [1,4) "+sub);
    System.out.println("11: "+ pets.containsAll(sub));//containsAll(listObj)判断是否包含listObj的全部对象(忽略顺序)
    Collections.sort(sub);//Collections.sort(list)对列表list进行排序(需要list包含的对象实现泛型接口Comparable&lt;&gt;)
    System.out.println("12: sorted sub "+ sub);
    System.out.println("13: "+ pets.containsAll(sub));
    Collections.shuffle(sub,rand);//Collections.shuffle(list,rand)将list按rand规则打乱
    System.out.println("14: shuffle sublist "+sub);
    System.out.println("15: "+pets.containsAll(sub));
    
    List&lt;Pet&gt; copy = new ArrayList&lt;&gt;(pets);
    sub = Arrays.asList(pets.get(1),pets.get(4));//获取pets的第一个和第4个对象,返回一个列表,传入sub
    System.out.println("16: sub: "+sub);
    copy.retainAll(sub);//retainAll(list)与list所有元素取交集
    System.out.println("17: "+copy);
    
    copy = new ArrayList&lt;&gt;(pets);//构造器传参,初始化list
    System.out.println(copy);
    copy.remove(2);//remove(index)移除index位置对象
    System.out.println("18: "+copy);
    copy.removeAll(sub);//removeAll(list)与list取差集,移除list中包含的元素
    System.out.println("19: "+copy);
    
    copy.set(1,new Pet("Toby"));//set(index,obj)将index位置元素替换成obj
    System.out.println("20: "+copy);
    
    copy.addAll(2,sub);//add(index,list)将list所有元素插入到index位置
    System.out.println("21: "+copy);
    System.out.println("22: "+copy.isEmpty());//isEmpty()判断是否非空
    copy.clear();//clear()移除所有元素
    System.out.println("23: "+ copy.isEmpty());
    
    pets.addAll(Pets.namePets(4));
    System.out.println("24: "+pets);
    Object[] o = pets.toArray();//toArray()转为数组
    System.out.println("25: "+ o[3]);
    Pet[] pas = pets.toArray(new Pet[0]);//toArray(T[])T[]为数组设置初始值
    System.out.println("26: "+ pas[3].name);
    }

    }
    class Pets{
    static ArrayList namePets(int i){ //返回含有将i个Pet对象的列表
    String[] names = new String[]{"Charlie","Max", "Buddy","Oscar",
    "Milo","Bella","Molly"," Coco" ,"Ruby" ,"Lucy"};
    Random random = new Random();
    ArrayList pets = new ArrayList<>();
    for (int j = 0; j < i; j++) {
    pets.add(new Pet(names[j]));
    }
    return pets;
    }

    }
    class Pet implements Comparable<Pet>{//继承泛型实现sort方法
        public Pet(String name) {
            this.name = name;
        }
        String name;
    @Override
    public String toString() {//重写toString方法实现打印
        return this.name;
    }
    
    @Override
    public int compareTo(Pet anotherPet) {//实现Comparable接口
            return this.name.compareTo(anotherPet.name);
    }
    }

迭代器是一个用于遍历并选择一个容器中元素的对象,而不必关心容器中的元素的底层结构。

Java中使用Iterator来表示迭代器对象

  • 使用iterator方法要求容器返回一个迭代器。Iterator将准备好返回序列的第一个元素

  • next()方法返回序列的下一个元素

  • hasNext()检查是否还有下一个元素

  • remove()移除序列最新返回的元素

    public class TestIterator {
    public static void main(String[] args) {
    ArrayList pets = Pets.namePets(9);
    System.out.println(pets);
    Iterator petIterator = pets.iterator();//use method list.iterator() to create
    while (petIterator.hasNext()){//判断
    Pet p = petIterator.next();//返回下一个元素
    System.out.print(p+"\t");
    }
    System.out.println();
    for (Pet p: pets) { //通过Iterator实现的forEach循环遍历 本质上还是是Iterator
    System.out.print(p+"\t");
    }

        petIterator = pets.iterator();
        for (int i = 0; i < 4; i++) {
            petIterator.next();//返回下一个元素(头部开始)
            petIterator.remove();//移除next()方法返回的元素,使用该方法必须先使用next()方法
        }
        System.out.println();
        System.out.println(pets);
    }

    }

使用迭代器时,不必关心序列底层结构,统一了对容器的访问方式

public class TestIterator1 {
    public static void displayContainer(Iterator<Pet> petIterator){
        while (petIterator.hasNext()){
            Pet p = petIterator.next();
            System.out.print(p+"\t");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        ArrayList<Pet> pets= Pets.namePets(6);
        LinkedList<Pet> petsLL = new LinkedList<>(pets);
        HashSet<Pet> petsHS = new HashSet<>(pets);
        TreeSet<Pet> petsTS = new TreeSet<>(pets);
        displayContainer(pets.iterator());
        displayContainer(petsLL.iterator()); //迭代器能够访问不同的容器
        displayContainer(petsHS.iterator());
        displayContainer(petsTS.iterator());
    }
}

List类的专用迭代器ListIterator

ListIterator添加了previous方法和hasPrevious方法实现了对前一个元素的访问以及存在性判断;

添加了set方法替换访问过的最后一个元素

public class TestListIterator {

    public static void main(String[] args) {
        List<Pet>pets = Pets.namePets(7);
        ListIterator<Pet> petListIterator = pets.listIterator();
        while (petListIterator.hasNext()){
            System.out.print(petListIterator.next()+"\t");
        }
        System.out.println();
        while (petListIterator.hasPrevious()){
            System.out.print(petListIterator.previous()+"\t");//前移动访问
        }
        System.out.println();
        petListIterator.next();
        petListIterator.set(new Pet("Scout"));//将第一个元素替换
        System.out.println(pets);
    }
}

LinkedListArrayList一样实现了基本的List接口,它在中间插入更加高效,在随机访问上要慢一些

LinkedList还添加了作为栈、队列双端队列的方法

public class TestLinkedList {
    public static void main(String[] args) {
        LinkedList<Pet> pets = new LinkedList<>(Pets.namePets(8));
        System.out.println(pets);
        //获取头部元素,前面二者完全相同,当为空时抛出NoSuchElementException,peek()方法返回null
        System.out.println("pets.getFirst(): "+pets.getFirst());
        System.out.println("pets.element(): "+pets.element());
        System.out.println("pets.peek(): "+pets.peek());
        //移除头部元素,前面二者完全相同,当为空时抛出NoSuchElementException,poll()方法返回null
        System.out.println("pets.remove(): "+pets.remove());
        System.out.println("pets.removeFirst(): "+pets.removeFirst());
        System.out.println("pets.poll(): "+pets.poll());
        //头部插入
        pets.addFirst(new Pet("Ollie"));
        System.out.println("After addFirst: "+pets);
        //尾部插入
        pets.offer(Pets.randomPet());
        System.out.println("After offer: "+pets);
        pets.add(Pets.randomPet());
        System.out.println("After add: "+pets);
        pets.addLast(Pets.randomPet());
        System.out.println("after addLast: "+pets);
        //移除尾部元素
        System.out.println("pets.removeLast(): "+pets.removeLast());

    }

}

栈通常是指“后进先出的容器”

LinckedList具有实现栈的全部功能的方法,因此可用LinkedList实现栈

但是如果只需要栈的行为,使用继承LinkedList的栈就不合适,因为会继承LinkedList的其他方法

Stack通常有这几类方法

  • push():接受T类型的对象,将其压入栈中

  • pop():移除栈顶元素并返回

  • peek():返回栈顶元素,但部移除

    public class TestStack {
    public static void main(String[] args) {
    Stack stringStack = new Stack<>();
    for (String s: "My dog has fleas".split(" ")) {
    stringStack.push(s);//入栈
    }
    System.out.println(stringStack);
    while (!stringStack.empty()){//empty()方法判断栈是否为空
    System.out.print(stringStack.pop()+"\t");//出栈
    }
    }
    }

练习:将字母压入栈“+”压入,“-” 取出打印

"+U+n+c---+e+r+t---+a-+i-+n+t+y---+-+r+u--+l+e+s"


public class TestStack01 {
    public static void main(String[] args) {

        char[] s = "+U+n+c---+e+r+t---+a-+i-+n+t+y---+-+r+u--+l+e+s".toCharArray();
        charStack(s);

    }
    public static Stack<Character> charStack ( char[] s){
        Stack<Character> characterStack = new Stack<>();
        for (int i = 0; i < s.length; i++) {
            System.out.println(characterStack);
            if (s[i] == '+') {//当遍历到字符数组为加号时,遍历后面元素,检测到非符号时压入栈中
                for (int j = i; j < s.length; j++) {
                    if (!(s[j] == '+' || s[j] == '-')) {
                        characterStack.push(s[j]);
                        break;
                    }
                }
            } else if (s[i] == '-') {//检测到'-'弹出元素
                characterStack.pop();
            }
        }
            return characterStack;
    }
}

Set不能保存相同元素,将多个相同实例添加到Set时,就会阻止这种重复现象

Set具有与Collection完全一样的接口,Set实际上就是Collection只是行为不同

public class TestSet {
    public static void main(String[] args) {
        Random random = new Random(47);
        Set<Integer> set = new HashSet<>();
        for (int i = 0; i < 10000; i++) {
            set.add(random.nextInt(30));

        }
        System.out.println(set);//HashSet输出无序
    }
}


public class TestTreeSet {
    public static void main(String[] args) {
        Set<Integer> set = new TreeSet<>();
        Random rand = new Random(47);
        for (int i = 0; i < 1000; i++) {
            set.add(rand.nextInt(30));
        }
        System.out.println(set);//TreeSet输出有序
    }
}

Set操作。

public class SetOperations {
    public static void main(String[] args) {
        HashSet<String> s1 = new HashSet<>();
        Collections.addAll(s1,"A B C D E F G H I J K L".split(" "));
        s1.add("M");
        System.out.println("Set1 contain H "+s1.contains("H"));
        System.out.println("Set1 contain N "+s1.contains("N"));
        HashSet<String> s2 = new HashSet<>();
        Collections.addAll(s2,"H I J K L".split(" "));
        System.out.println("set2 in set1 "+s1.containsAll(s2));
        s1.remove("H");
        System.out.println("Set1: "+s1);
        System.out.println("Set2: "+s2);
        System.out.println("set2 in set1 "+s1.containsAll(s2));
        s1.removeAll(s2);
        System.out.println("set2 removed from set1 "+ s1);
    }
}
  • Map不是collection的子接口或者实现类。Map是一个接口。

  • Map用于保存具有“映射关系”的数据。每个Entry都持有键-值两个对象。其中,Value可能重复,但是Key不允许重复(和Set类似)。

  • Map可以有多个Value为null,但是只能有一个Key为null。

实现类

HashMap

和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准一样: 两个key通过equals()方法比较返回true、 同时两个key的hashCode值也必须相等

LinkedHashMap

LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序区分)

Properties

Properties对象在处理属性文件时特别方便(windows平台的.ini文件)。Properties类可以把Map对象和属性文件关联,从而把Map对象的key - value对写入到属性文件中,也可把属性文件中的“属性名-属性值”加载进Map对象中。

TreeMap

TreeMap是一个红黑树结构,每个键值对都作为红黑树的一个节点。TreeMap存储键值对时,需要根据key对节点进行排序,TreeMap可以保证所有的key-value对处于有序状态。 同时,TreeMap也有两种排序方式:自然排序、

public class TestMap {
    public static void main(String[] args) {
        Map<String,Pet> petMap = new HashMap<>();
        petMap.put("MyCat",new Pet("Molly"));
        petMap.put("MyDog",new Pet("Ginger"));
        System.out.println(petMap);
        Pet dog = petMap.get("MyDog");
        System.out.println(dog);
        System.out.println(petMap.containsKey("MyDog"));
        System.out.println(petMap.containsValue(dog));

        System.out.println(petMap.entrySet());//entrySet() 方法返回映射中包含的映射的 Set 视图
        System.out.println(petMap.values() instanceof Collection);// 获取值返回一个Collection

        ArrayList<String> arrayList = new ArrayList<>();
        System.out.println(Arrays.asList(1,2,3) instanceof List);
    }
}

此接口用于模拟“队列”数据结构(FIFO)。新插入的元素放在队尾,队头存放着保存时间最长的元素

Queue接口与Collections接口中的方法是独立的

实现类

PriorityQueue—— 优先队列(类)

其实它并没有按照插入的顺序来存放元素,而是按照队列中某个属性的大小来排列的。故而叫优先队列。

Deque——双端队列(接口)

  • ArrayDeque

    基于数组的双端队列,类似于ArrayList有一个Object[] 数组。

  • LinkedList

  1. LinkedList实现

    public class TestLinkedListQueue {
    public static void printQ(Queue q){
    while (q.peek()!=null){//peak()方法返回头部元素
    System.out.print(q.peek()+"\t");//remove()方法移除并返回头部元素
    q.remove();
    }
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            queue.offer(random.nextInt(i+10)); //offer()方法入队
        }
        printQ(queue);
        System.out.println();
        Queue<Character> characters = new LinkedList<>();
        for (char c:"FuckYOU!!!!".toCharArray()){
            characters.offer(c);
        }
        printQ(characters);
    }

    }

  2. PriorityQueue

    优先队列会根据元素的优先级对每个插入的元素进行排序,弹出的每个元素为此时优先级最高的元素

    优先队列的排序方式为默认排序方式,也可以提供Comparator来修改排序

    //优先队列2参数构造器,容量+比较方法
    public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }
    
    
    public class TestPriorityQueue {
        public static void main(String[] args) {
            PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
            Random rand = new Random();
            for (int i = 0; i < 10; i++) {
                priorityQueue.offer(rand.nextInt(i+10));
            }
            TestLinkedListQueue.printQ(priorityQueue);
            List<Integer> integerList = Arrays.asList(99,2,22,100,2,7,33,1276);
            PriorityQueue<Integer> priorityQueue1 = new PriorityQueue<>(integerList);
            TestLinkedListQueue.printQ(priorityQueue1);
        priorityQueue1 = new PriorityQueue&lt;&gt;(integerList.size(), Collections.reverseOrder());//自定义优先级
        priorityQueue1.addAll(integerList);
        TestLinkedListQueue.printQ(priorityQueue1);
    
        String fact = "SB ZHI YUAN ZHE HUO DONG LANG FEI YE DE SHI JIAN";
        List&lt;String&gt; strings = Arrays.asList(fact.split(""));
        PriorityQueue&lt;String&gt; priorityQueue2 = new PriorityQueue&lt;String&gt;(strings);
        int pq2Size = priorityQueue2.size();
        TestLinkedListQueue.printQ(priorityQueue2);
        System.out.println(pq2Size);
    
        PriorityQueue&lt;String&gt; priorityQueue3 = new PriorityQueue&lt;&gt;(pq2Size,Collections.reverseOrder());
        priorityQueue3.addAll(strings);
        TestLinkedListQueue.printQ(priorityQueue3);
    
    }
    }

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器

你可能感兴趣的文章