java入门篇11 --- 集合
Posted 灬
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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来模拟栈的
以上是关于java入门篇11 --- 集合的主要内容,如果未能解决你的问题,请参考以下文章