zoukankan      html  css  js  c++  java
  • java入门篇11 --- 集合

    无论什么语言,集合应当是我们最常用的一种类型啦,大体上分为有序列表、map、sey、队列

    首先先来看一下有序列表,

    List内部跟数组一样也是按照先后顺序排放的,但对于增删,非常方便,list的实现大多是使用ArrayList实现的,先来看一下List的源码,这里面有一个<E>,这个就是泛型,java是面向对象语言,他在运行期间,才会将我们的类进行初始化,因此,就利用这一特性,我们输入指定的引用类型,注意必须是引用类型,基本类型不是类,JVM在编译是,会把它当作object,然后再运行期间就会帮我们转化为指定的类型

    // 一个接口
    public interface List<E> extends Collection<E> {
        int size();  // 大小
        boolean isEmpty();  // 是否为空
        boolean contains(Object o);  // 是否包含
        Iterator<E> iterator();  // 是否可迭代
        Object[] toArray();  // 转化为数组,返回就是object[]
        <T> T[] toArray(T[] a);  // 转化为数组,返回就是指定的类型[]
        boolean add(E e);  // 增加,返回true,false
        boolean remove(Object o);  // 删除,返回bollean
        boolean containsAll(Collection<?> c);  // 包含
        boolean addAll(Collection<? extends E> c);// 添加
        boolean addAll(int index, Collection<? extends E> c);  // 添加指定位置
        boolean removeAll(Collection<?> c);  // 删除
        @SuppressWarnings({"unchecked", "rawtypes"})
        default void sort(Comparator<? super E> c) {
            Object[] a = this.toArray();
            Arrays.sort(a, (Comparator) c);
            ListIterator<E> i = this.listIterator();
            for (Object e : a) {
                i.next();
                i.set((E) e);
            }
        }  // 拍讯,因此想要排序,必须实现Comparator接口
        void clear(); // 情况
        boolean equals(Object o);  // 判断是否相等
        int hashCode();  // 获取这个code, 返回值int
        E get(int index);// 获取指定下表的对象
        E set(int index, E element);// 重置
        void add(int index, E element);  // 添加
        E remove(int index);  // 删除
        int indexOf(Object o);  // 获取某个对象的下表
        int lastIndexOf(Object o);  // 获取最后一个对象的下表
        @SuppressWarnings("unchecked")  // 这个传入为空,就会报错
        static <E> java.util.List<E> of() {
            return (java.util.List<E>) ImmutableCollections.ListN.EMPTY_LIST;
        }
        static <E> java.util.List<E> of(E e1, E e2, E e3, E e4, E e5) {  // 初始化指定的列表
            return new ImmutableCollections.ListN<>(e1, e2, e3, e4, e5);
        }
    }

    那么,我们来看一下上面提到的一些方法吧

    import java.util.*;
    import java.util.List;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            // List<int> s  = new ArrayList<>();  // java: 意外的类型 需要: 引用 找到:    int
            List<String> s = new ArrayList<>();
            System.out.println(s.isEmpty());  // true判断是否为空
            s.add("a");  // 添加
            // s.add(1);  //   java: 不兼容的类型: int无法转换为jåava.lang.String, 因为已经指定类型,所以只能传入指定类型的
            s.add("b");
            System.out.println(s.add("c"));  // true
            System.out.println(s.size());  // 3
            System.out.println(s);  // [a, b, c]
            System.out.println(s.contains("a"));  // true 包含关系
            List<String> s1 = List.of("d", "e");  // 这个返回的只是一个只读的List,因为List只是一个接口
            // s1.add("m"); // java.lang.UnsupportedOperationException
            List<String> s2 = List.of("f", "g");
            s.addAll(s1);
            System.out.println(s);  // [a, b, c, d, e] 插入一个对象
            s.addAll(3, s2);
            System.out.println(s);  // [a, b, c, f, g, d, e]  在指定位置插入
            s.remove("f");
            System.out.println(s);  // [a, b, c, g, d, e]  删除
            System.out.println(s.get(1));  // b  获取指定下表的元素
            // String[] m = s.toArray();  // java: 不兼容的类型: java.lang.Object[]无法转换为java.lang.String[],这个是因为不支持的,随意这个运行之前就是object
            String[] m1 = new String[3];
            String[] m2 = new String[9];
            String[] m3 = s.toArray(m1);  // 可以这样转化,List会把值赋值给传入对象,但是如果数字不够长,List会为他生成新的对象
            String[] m4 = s.toArray(m2);  // 可以这样转化,
            for (String i : m1) {
                System.out.println(i);
            }  // null null null 数组不够长,我们应该清楚,数组扩容之后,会生成一个新对象,愿对象就会被清空
            for (String i : m3) {
                System.out.println(i);
            }  // a b c g d e 这个就是被扩容之后的新对象,所以要记得写返回值
            for (String i : m2) {
                System.out.println(i);
            }  // a b c g d e null null null  这个数组定义的够长,所有值是传进去了
            for (String i : m4) {
                System.out.println(i);
            } // a b c g d e null null null
            // 一般情况下,我们肯定希望正好,可以结合上size或者直接为0
            String[] m5 = s.toArray(new String[0]);
            String[] m6 = s.toArray(new String[s.size()]);
            for (String i : m5) {
                System.out.println(i);
            } // a b c g d e 正好
            for (String i : m6) {
                System.out.println(i);
            } // a b c g d e 正好
            // List 的循环,for each的方法帮助我们封装了迭代,原始应该是这样的
            for (Iterator<String> ss = s.iterator(); ss.hasNext(); ) {
                String sss = ss.next();
                System.out.println(sss);
            } // a b c g d e
            // 如上面所说,for帮助我们做了封装,所以可以直接这样写
            for (String ss : s) {
                System.out.println(ss);
            } // a b c g d e
        }
    }

    说完了List,接下来我们来看一下map,map是key-value的一种数据结构,他的方法类是HashMap,源码感觉差不太多,都是一些接口定义了一些方法,我们直接看使用,map的实现方法是它使用一个比较大的数组,来存储所有的value,然后计算key的值(hascode),然后根据这个作为索引,将value存储在指定位置,因此如果想用使用自己的类来dingyikey,必须实现equalshenhascode这两个方法,因为这个不常用,就不再展示,但我们既然知道这个原理,就能想象的到map是无序的。接下来看一下map的常用操作

    import java.util.*;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            Map<String, Integer> s = new HashMap<>();
            s.put("a", 1);  // 添加
            s.put("b", 2);
            s.put("c", 3);
            System.out.println(s.put("d", 4)); // null
            System.out.println(s.put("d", 4)); // 4  如果重复,就会把原来的值替换,并抛出原来的值
            System.out.println(s.get("a"));  // 1 获取
            System.out.println(s.containsKey("f"));  // false
            System.out.println(s.getOrDefault("f", 1));  // 1 如果获取失败,就会给出默认值
            System.out.println(s.remove("f"));  // null  删除
            System.out.println(s.remove("a"));  // 1  如果有删除,就会返回值
            // 循环所有的key
            for (String key : s.keySet()) {
                System.out.println(key);
                System.out.println(s.get(key));
            }
            // 循环所有的key-value
            for (Map.Entry<String, Integer> ss : s.entrySet()) {
                System.out.println(ss);
                System.out.println(ss.getKey() + ss.getValue());
            }
        }
    }

    另外还有一种实现map的方法是枚举map,如果对于一些比较少的,可以直接使用这个类型,它并非使用key的code进行安排缩阴的,而是直接使用key,因此效率会更高

    import java.time.DayOfWeek;
    import java.util.*;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            Map<DayOfWeek, String> map = new EnumMap<>(DayOfWeek.class);
            map.put(DayOfWeek.MONDAY, "星期一");
            map.put(DayOfWeek.WEDNESDAY, "星期二");
            map.put(DayOfWeek.FRIDAY, "星期五");
            System.out.println(map.get(DayOfWeek.FRIDAY));  // 星期五
            System.out.println(map);  // {MONDAY=星期一, WEDNESDAY=星期二, FRIDAY=星期五}
        }
    }

    既然上面提到的map是无序的,就如同python中dict是无序的,但还是有有序字典OrderDict,因此java也肯定有有序map,他实现的接口是SortMap, 实现类是TreeMap,但是如果要使用自己的定义的类作为key,请记得要实现compare方法

    import java.util.Comparator;
    import java.util.Map;
    import java.util.SortedMap;
    import java.util.TreeMap;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            SortedMap<String, Integer> s = new TreeMap<>(); // 初始化一个有序map
            s.put("a", 1);  // 添加
            s.put("b", 2);
            s.put("c", 3);
            System.out.println(s);  // {a=1, b=2, c=3}
            // 循环打印
            for (Map.Entry<String, Integer> ss : s.entrySet()) {
                System.out.println(ss);
            }  // a=1 b=2 c=3
            // 初始化一个带我们自定义排序方法的有序map,查看结构跟上面相反
            SortedMap<String, Integer> s1 = new TreeMap<>(new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                    return -o1.compareTo(o2);
                }
            });
            s1.put("a", 1);
            s1.put("b", 2);
            s1.put("c", 3);
            System.out.println(s1);  // {c=3, b=2, a=1}
            for (Map.Entry<String, Integer> ss : s1.entrySet()) {
                System.out.println(ss);
            }  // c=3 b=2 a=1
        }
    }

    然后我们再来看一下set,集合,他最出名的不就是去重,他有两个实现类,一个是HashSet无序,另外一个是TreeSet有序,而有序集合里面的元素如果没有实现compaer接口,需要初始化时传入一个自定义的比较,跟有序集合类似,就不再赘述

    import java.util.*;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            // 无序集合
            Set<String> s = new HashSet<>();
            s.add("c");
            s.add("b");  // 添加
            s.add("a");
            System.out.println(s);  // [a, b, c]
            System.out.println(s.contains("a"));  // true  包含
            System.out.println(s.remove("d"));  // false  删除,没有删除,返回false
            System.out.println(s.remove("a"));  // true
            System.out.println(s);  // [b, c]
            for (String ss : s) {
                System.out.println(ss);
            }  // b c
            // 有序集合
            Set<String> s1 = new TreeSet<>();
            s.add("a");
            s.add("b");
            s.add("c");
            System.out.println(s);  // [a, b, c]
            for (String ss : s) {
                System.out.println(ss);
            }  // a b c
        }
    }

    接下来看一下队列,队列分为几种,一个是FIFO--Queue,另外一个是有优先级的 PriorityQueue,而这个是必须实现compaer接口,否则没办法选择优先级, 还有双端队列 -- Deque

    我们来看一下实例

    import java.util.*;
    
    public class HelloWorld {
        public static void main(String[] args) throws Exception {
            // FIFO队尾进,队首出
            Queue<String> q1 = new LinkedList<>();  // 这个 LinkedList 也实现了List接口,根据需要选择,这个就是链表,但是作为List来用,没有特许需求的话,有点吗,他是按照链表来存储的
            // 两端均可进可出
            Deque<String> q2 = new LinkedList<>();
            // 根据默认的或自定义对比方法,出队列,String有compaer方法,我只是自定义了一个反序的
            Queue<String> q3 = new PriorityQueue<>(new Comparator<String>() {
                public int compare(String a, String b) {
                    return -a.compareTo(b);
                }
            });
            // add 添加方法,如果添加失败就报错,比如队列满了
            // FIFO添加对象方法
            q1.add("a");
            q1.add("b");
            q1.add("c");
            System.out.println(q1);  // [a, b, c]
            for (String qq : q1) {
                System.out.println(qq);
            }  // a b c
            // 双端队列添加方法
            q2.addFirst("a");
            q2.addFirst("b");
            q2.addLast("d");
            q2.addLast("c");
            System.out.println(q2);  // [b, a, d, c]
            for (String qq : q2) {
                System.out.println(qq);
            }  // b a d c
            // 优先级队列添加方法
            q3.add("a");
            q3.add("b");
            q3.add("c");
            System.out.println(q3);  // [c, a, b]
            for (String qq : q3) {
                System.out.println(qq);
            }  // c a b
            // offer 添加方法,会返回boolean值,告知是否添加成功,不会报错
            q1.offer("a");
            q1.offer("b");
            System.out.println(q1.offer("c"));  // true
            System.out.println(q1);  // [a, b, c, a, b, c]
            for (String qq : q1) {
                System.out.println(qq);
            }  // a b c
            // 双端队列添加方法
            q2.offerFirst("a");
            q2.offerFirst("b");
            q2.offerLast("d");
            q2.offerLast("c");
            System.out.println(q2);  // [b, a, b, a, d, c, d, c]
            for (String qq : q2) {
                System.out.println(qq);
            }  // b a b a d c d c
            // 优先级队列添加方法
            q3.offer("a");
            q3.offer("b");
            q3.offer("c");
            System.out.println(q3);  // [c, b, c, a, a, b]
            for (String qq : q3) {
                System.out.println(qq);
            }  // c b c a a b
            // 获取首元素并删除
            // 删除失败会报错
            Queue<Integer> i = new LinkedList<>();
            // i.remove();  // java.util.NoSuchElementException
            q1.remove();
            System.out.println(q1);  // [b, c, a, b, c]
            q2.removeFirst();
            System.out.println(q2);  // [a, b, a, d, c, d, c]
            q2.removeLast();
            System.out.println(q2);  // [a, b, a, d, c, d]
            q3.remove();
            System.out.println(q3);  // [c, b, b, a, a]
            // 删除失败不会报错,会返回false 或者 null
            System.out.println(i.poll());
            System.out.println(q1.poll());  // b
            System.out.println(q1);  // [c, a, b, c]
            q2.pollFirst();
            System.out.println(q2);  // [b, a, d, c, d]
            q2.pollLast();
            System.out.println(q2);  // [b, a, d, c]
            q3.poll();
            System.out.println(q3);  // [b, a, b, a]
            // 取首元素但是不会删除
            // 删除失败会报错
            System.out.println("----");
            // i.element();  // java.util.NoSuchElementException
            System.out.println(q1.element());  // c
            System.out.println(q1);  // [c, a, b, c]
            q1.element();
            System.out.println(q1);  // [c, a, b, c]
            q2.getFirst();
            System.out.println(q2);  // [b, a, d, c]
            System.out.println(q2.getFirst());  // b
            System.out.println(q2);  // [b, a, d, c]
            System.out.println(q2.getLast());  // c
            System.out.println(q2);  // [b, a, d, c]
            q2.getLast();
            System.out.println(q2);  // [b, a, d, c]
            q3.element();
            System.out.println(q3);  // [b, a, b, a]
            q3.element();
            System.out.println(q3);  // [b, a, b, a]
            // 删除失败不会报错,会返回false 或者 null
            System.out.println(i.peek());  // null
            System.out.println(q1.peek());  // c
            System.out.println(q1);  // [c, a, b, c]
            System.out.println(q1.peek());  // c
            System.out.println(q1);  // [c, a, b, c]
            System.out.println(q2.peekFirst());  // b
            System.out.println(q2);  // [b, a, d, c]
            q2.peekFirst();
            System.out.println(q2);  // [b, a, d, c]
            System.out.println(q2.peekLast());  // c
            System.out.println(q2);  // [b, a, d, c]
            q2.peekLast();
            System.out.println(q2);  // [b, a, d, c]
            q3.peek();
            System.out.println(q3);  // [b, a, b, a]
            q3.peek();
            System.out.println(q3);  // [b, a, b, a]
    
            // 双端队列还有 pop 的 取出队首且删除的犯法,但取不到就会报错
            System.out.println(q2.pop());  // b
            System.out.println(q2.pop());  // a
            System.out.println(q2.pop());  // d
            System.out.println(q2.pop());  // c
            //System.out.println(q2.pop());  // java.util.NoSuchElementException
            // 还有push增加方法
            q2.push("a");
            q2.push("b");
            System.out.println(q2);
            // 因此我们可以使用Deque来模拟栈
            Deque<String> q4 = new LinkedList<>();
            // 模拟压栈
            q4.push("a");
            q4.push("b");
            // 模拟出栈
            System.out.println(q4); // [b, a]
            System.out.println(q4.pop());  // b 删除队首,并跑操
            System.out.println(q4);  // [a]
            System.out.println(q4.peek()); // a 只取队首的值,不删除
            System.out.println(q4); // [a]
        }
    }

    我们确实是可以使用Deque来模拟栈的

  • 相关阅读:
    delphi 多线程定时执行程序如何写
    delphi 把多个线程的请求阻塞到另一个线程 TElegantThread
    delphi 对TThread扩充TSimpleThread
    Delphi 线程Timer (TThreadTimer)
    vue-01-插值表达式、事件修饰符
    ORA-12516:监听程序找不到服务协议堆栈要求的可用处理程序(转)
    Io 异常: The Network Adapter could not establish the connection(转)
    "Cannot read property 'xxx' of undefined" js问题之某属性未定义
    数据库用日期作为条件来查询数据
    Docker Registry配置客户端
  • 原文地址:https://www.cnblogs.com/yangshixiong/p/12172253.html
Copyright © 2011-2022 走看看