java中的集合就像是一个容器一样,专门用来存储java对象的引用,这些对象可以是任意的数据类型并且长度可变,集合类位于java.util包中。
java集合按照其存储结构可以分为两大类,一个是单列集合Collection和双列集合Map。
对单列集合Collection和双列集合Map的解释:
Collection集合是单列集合的根接口,用于存储一系列符合某种规则的元素。Collection中有两个重要的子接口:List和Set。
Map集合是双列集合的根接口,用于存储具有键值对映射关系(key value)的元素。Map集合中每个元素都包含一对键值,而且key是唯一的,可以通过 key访问value。
一、Collection ------List接口和Set接口的根接口。(相当于父类的作用吧)
(一)List接口
List集合的特点是元素有序、元素可重复;
List接口继承自Collection接口,在List集合中允许出现重复的元素、所有的元素都是以一种线性方式存储的,程序中可通过索引(下标)来访问集合中的指定元素。List集合的元素有序,即元素的取出顺序和存入顺序一致!
1.ArrayList-----(适合大量遍历和查找元素的情况)
ArrayList内部封装了一个长度可变的数组对象,当存入的元素超过数组的长度时,ArrayList会在内存中分配更大的数组来存储这些元素,故ArrayList可以看为是一个长度可变的数组。.ArrayList内部存储结构形式导致了.ArrayList在增加或者删除元素的时候会创建新的数组效率比较低,故不适合大量的增删操作。 通过索引的方式访问元素,在遍历以及查找的时候有优势,适合大量遍历和查找元素的情况。
例子:(注释在代码中!)
package coll; import java.util.ArrayList; import java.util.Iterator; public class ArrayList_Test { /* * Collection接口有两个重要接口:一是List,二是Set. * List集合的特点是元素有序、可重复; Set集合的特点是元素无序且不可重复。 * * ArrayList集合类 是Collection接口的子接口List的实现类之一。 * ArrayList使用于需要大量遍历和查找元素的情况。因为ArrayList是通过索引的方式来访问元素。 */ public static void main(String[] args) { //创建ArrayList集合 ArrayList list = new ArrayList(); //向集合中添加元素 list.add("stu1"); list.add("stu2"); list.add("stu3"); list.add("stu4"); System.out.println("集合的长度:"+list.size()); System.out.println("第二个元素是:"+list.get(1)); //集合的遍历: //使用Iterator遍历集合 Iterator iterator_ArrayLsit = list.iterator(); while (iterator_ArrayLsit.hasNext()) { Object obj = iterator_ArrayLsit.next(); System.out.println(obj); } System.out.println("使用Iterator遍历集合完毕!"); //使用foreach遍历集合: 注:foreach循环不能修改数组和集合,因为并没有下标以及其它方式 提供修改的途径 for (Object object : list) { System.out.println(object); } System.out.println("使用foreach遍历集合完毕!"); } }
2.LinkedList–适合大量增删元素的情况
LinkedList的内部结构是有两个Node类型的first和last属性维护一个双向循环链表,链表中的每一个元素都用引用的方式来记住它的前一个元素和后一个元素,至此,所有元素也就彼此连接起来了嘛。。。插入或者删除一个元素的时候,修改引用关系即可,也就是那种覆盖、跳过、挪动的作用(哎呀,反正就是这样,就是类似这种说法: 把这个东西的指向由 指到下一个 改成 指到下一个的下一个,然后断开 下一个 到 下一个的下一个 之间的联系)。
例子:(注释在代码中!)
package coll; import java.util.LinkedList; public class LinkedList_test { /* * Collection接口有两个重要接口:一是List,二是Set. * List集合的特点是元素有序、可重复; Set集合的特点是元素无序且不可重复。 * * LinkedList集合类 是Collection接口的子接口List的实现类之一。 * LinkedList使用于需要大量增删元素的情况。因为LinkedList的结构类似一个双向循环链表。 */ public static void main(String[] args) { //创建LinkedList集合 LinkedList link = new LinkedList(); //添加元素 link.add("stu1"); link.add("stu2"); link.add("stu3"); link.add("stu4"); System.out.println(link); //输出LinkedList集合中的所有元素 link.offer("offer"); //从尾部添加元素 link.push("push"); //从头部添加元素 System.out.println("添加元素之后: "+link); //获取元素 Object object = link.peek(); //获取集合(列表的)的第一个元素 System.out.println(object); //删除元素 link.removeFirst(); //删除集合第一个元素 System.out.println("删除第一个元素之后: "+link); link.pollLast(); //删除集合最后一个元素 System.out.println("删除最后一个元素之后: "+link); } }
(二)Set接口
Set集合的特点是元素无序、不可重复;
Set接口同样是继承自Collection接口,与Collection接口中的方法基本一致。Set接口中的元素无序,并且会以某种规则保证存入的元素不出现重复。
1.HashSet
HashSet是根据对象的哈希值来确定元素在集合中的存储的位置,具有优秀的存取和查找能力。她所存储的元素是不可重复的,元素是无序的。
存储过程:向HashSet集合对象添加一个元素的时候,首先调用该元素的hashCode()方法返回对应的哈希值进行计算确定元素的存储位置,然后再去调用元素的equals()方法保证没有重复元素。
例子:
package coll; import java.util.HashSet; /* * Collection接口有两个重要接口:一是List,二是Set. * List集合的特点是元素有序、可重复; Set集合的特点是元素无序且不可重复。 * * HashSet是Set接口的一个实现类,她所存储的元素是不可重复的,并且元素都是无顺序的。 * * HashSet中添加一个元素时,首先调用该元素的hashCode()方法确定元素的存储的位置,然后再调用元素对象的equals()方法来确保该位置没有重复元素。 * 当然,可以重写根据自己需要重写上面这两个方法 */ public class HashSet_demo{ public static void main(String[] args) { HashSet hs = new HashSet(); Student stu1 = new Student("1", "jack"); Student stu2 = new Student("2", "rowk"); Student stu3 = new Student("1", "jack"); //向HashSet集合中添加对象 hs.add(stu1); hs.add(stu2); hs.add(stu3); // System.out.println(hs); hs.forEach(o -> System.out.println(o)); //使用lambda表达式将其元素打印 ; o只是一个变量的作用,代表了hs里面的元素 的对象 } } class Student{ private String id; private String name; public Student(String id,String name) { this.id = id; this.name = name; } //重写toString()方法 public String toString(){ return id+":"+name; } //重写hashCode()方法 public int hashCode(){ return id.hashCode(); //返回id属性的哈希值 // 哈希值和地址值是不一样的,哈希值是通过哈希算法散列得来的,而地址值是通过是和物理层面有关,是系统分配的,是不存在相同的, // 哈希值是可以通过强制手段设置为相同的,也就是说哈希值是一种逻辑上的确保唯一性,而地址值就是物理上确保唯一性。 } //重写对象比较方法 equals方法 public boolean equals(Object obj){ if (this == obj) { //this表示本对象,比如你这样调用equals函数:stu.equals(stu1),this就表示stu return true; //假如当前两个对象都是引用的对象才相等,然后返回true。 } if (!(obj instanceof Student)) { return false; //假如obj这个对象不是Student类型的对象,返回false. } Student stu = (Student) obj; boolean b = this.id.equals(stu.id); return b; //将obj对象的类型强制转换成Student类型的对象,判断当前id与obj对象(现在已经是Student类型)的id进行比较并返回比较结果。 } }
2.TreeSet
TreeSet是以二叉树的方式来存储元素,可以实现对集合的的元素进行排序!
TreeSet的内部结构存储是平衡二叉树,使用平衡二叉树可以保证TreeSet中没有重复的元素,还可以对元素进行排序。
这个过程是 存入新元素的时候,这个元素会跟最顶层元素相比较,若小于最顶层元素,则进入左边分支,继续执行(继续比较)下去,直到最后一个元素,如果小于最后一个元素则放在其左子树上,如果大于最后一个元素则放在右子树上; 若大于则进入右分支,道理和左边的一样。
当向TreeSet中存入一个元素时,会调用Comparable接口中的compareTo方法将该元素与其它元素进行比较,最后将它插入到有序的对象序列中;当然,也可以自己指定排序的规则,就是使用Comparator接口重写compare方法。
例子:(注释在代码中) 例子按照字符串的长度进行定制排序
package coll; import java.util.Comparator; import java.util.TreeSet; public class TreeSet_demo { public static void main(String[] args) { //创建集合时传入Comparator接口实现定制排序规则 TreeSet ts = new TreeSet(new MyComparetor()); ts.add("Jons"); ts.add("Helena"); ts.add("EQ"); System.out.println(ts); //创建序列时通过Lambda表达式来定制排序规则 TreeSet ts2 = new TreeSet((o1 , o2) ->{ String s1 = (String)o1; String s2 = (String)o2; return s1.length()-s2.length(); }); ts2.add("chen"); ts2.add("cen"); ts2.add("c"); System.out.println(ts2); } } class MyComparetor implements Comparator{ //自定义一个排序的方式然后抛出接口 @Override public int compare(Object o1, Object o2) { //自定义排序方式 String s1 = (String)o1; String s2 = (String)o2; int temp = s1.length()-s2.length(); return temp; } }
二、Map
Map接口是双列集合,key-value型,也就是映射关系。一个键对象key唯一对应一个值对象value,但是一个值对象value可以有多个键对象key。此外,key和value可以是任意数据类型,键对象key不允许重复。
(一)HashMap
HashMap存储键值映射关系,该集合的键和值允许为空,但是键不能重复,而且集合中的元素是无序的。
HashMap的底层存储结构:由哈希表结构(大致就是数组+链表,主体结构是数组)组成,链表主要是为了解决哈希值冲突而存在的分支的结构,HashMap对于元素的增删查改的操作效率都比较高。
例子:(说明在注释里面)
package map; import java.util.HashMap; import java.util.Iterator; import java.util.Set; /* * Map集合用于存储具有键key、值value 对 映射关系的元素。类似于json字符串或者python里面的字典。 * HashMap的底层是哈希表结构组成的(也就是数组+链表),所以HashMap集合对于元素的增删查改的效率很高。 * */ public class HashMap_test { public static void main(String[] args) { //创建HashMap对象 HashMap map = new HashMap(); //存储元素 map.put("1", "java"); map.put("0", "C++"); map.put("3", "scala"); map.put("4", "Python"); map.put("9", "R"); map.put("3", "C++"); // key=3,value=scala会被后面的 key=3的value=c++给覆盖 //一个key只对应一个值,但是一个值可以对应多个key System.out.println(map); //查看键对象是否存在 System.out.println("判断键是否存在:"+map.containsKey("1")); //获取键对象映射的值 System.out.println("使用键对象去获取对应的值:"+map.get("1")); //获取 集合中的键对象集合和 值对象 集合 System.out.println(map.keySet()); System.out.println(map.values()); //调换掉 指定的键对象 映射的值 map.replace("9", "JavaScript"); System.out.println(map); //删除指定键对象映射的 键值对元素 意思就是使用键名称去删除这个键所在的键值对 map.remove("3"); System.out.println(map); //遍历map集合 //1使用Iterator迭代器遍历map集合 Set keySet = map.keySet(); Iterator it = keySet.iterator(); while (it.hasNext()) { Object key = (Object) it.next(); Object value = map.get(key); System.out.println(key+" "+value); } System.out.println("Iterator遍历成功!"); //使用forEach()方法遍历集合 map.forEach((key,value) -> System.out.println(key+":"+value)); System.out.println("使用forEach+lambda遍历完成!"); } }
(二)TreeMap
TreeMap是用来存储键值对映射关系的,并且不允许出现重复的键。
TreeMap内部结构:二叉树(可保证键的唯一性,因为一个顶点的位置是不能存在两个点的),与TreeSet集合存储的原理是一样的按照某种顺序排列。与TreeSet一样,TreeMap可以通过自定义比较器的方式对所有的键进行定制排序。
例子 :
package map; import java.util.Comparator; import java.util.Map; import java.util.TreeMap; /* * TreeMap也是存储键值映射关系的,并且不允许出现重复的键。 */ public class TreeMap_test { public static void main(String[] args) { Map map = new TreeMap(new MyComparator()); map.put("1", "java"); map.put("2", "C++"); map.put("3", "python"); System.out.println(map); } } class MyComparator implements Comparator{ @Override public int compare(Object o1, Object o2) { String key1 = (String) o1; String key2 = (String) o2; return key2.compareTo(key1); //将key2与key1比较并返回 } }