JAVA集合Collection与Map
定西集合框架概述
数组的特点与弊端
特点
- 数组一旦初始化,长度就已经确定了
 
- 数组中的多个元素是依次紧密排列的,有序的,可重复
 
- 数组一旦初始化完成,其元素的类型就是确定的,不是此类型的元素,就不能添加到数组中
 
- 元素的类型既可以是基本数据类型,也可以是引用数据类型
 
弊端
- 数组一旦初始化,长度就已经不可变了
 
- 数组中存储数据特点的单一性,对于无序的,不可重复的场景的多个数据就不行了
 
- 数组中可用的方法,属性都极少
 
- 针对于数组中元素的删除,插入操作,性能较差(尾部添加性能并不差)
 
Java集合框架体系
java.util.Collection:存储一个一个数据
- List
- 存储有序的,可重复的数据
 
- ArrayList
 
- LinkedList
 
- Vector
 
 
- Set(底层其实就是Map,只使用了Map的键,来保证唯一,不可重复)
- 存储无序的,不可重复的数据
 
- HashSet
 
- LinkedHashSet
 
- TreeSet
 
 
java.util.Map:存储一对一对数据
- HashMap
 
- LinkedHashMap
 
- TreeMap
 
- Hashtable
 
- Properties
 
Collection接口
add(Object obj)/addAll(Collection coll)1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | 
 
 
  @Test public void test1() {     Collection collection = new ArrayList();     collection.add("aa");     collection.add("bb");     collection.add(123);     collection.add(new Object());     collection.add(new Person("tom", 12));     System.out.println(collection);
      Collection collection1 = new ArrayList();     collection1.add("cc");     System.out.println(collection1.size());     collection1.addAll(collection);     System.out.println(collection1.size());     System.out.println(collection1); }
 
  | 
 
size(),isEmpty(),contains(Object obj),containsAll(Collection coll),equals()1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | 
 
 
 
 
 
  @Test public void test2() {     Collection collection = new ArrayList();     collection.add("aa");     collection.add("bb");     collection.add(128);     collection.add(new Person("111", 123));     System.out.println(collection.isEmpty());          System.out.println(collection.contains(128));          System.out.println(collection.contains(new Person("111", 123)));
      Collection coll1 = new ArrayList();     coll1.add("aa");     coll1.add("cc");     System.out.println(collection.containsAll(coll1)); }
 
  | 
 
clear(),remove(),removeAll(),retainAll()1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
   | @Test public void test3() {     Collection coll1 = new ArrayList();     coll1.add("AA");     System.out.println(coll1);     coll1.clear();     System.out.println(coll1);
      coll1.add(new Person("tom", 11));     coll1.add(new Person("tom", 11));          coll1.remove(new Person("tom", 11));     System.out.println(coll1);
           coll1.add("AA");     coll1.add(111);
      Collection coll2 = new ArrayList();     coll2.add("AA");     coll2.add("BB");     coll2.add("CC");               
           coll1.retainAll(coll2);     System.out.println(coll1);
  }
   | 
 
Object[] toArray():返回包含当前集合中所有元素的数组 
hashCode():获取集合对象的哈希值 
iterator():返回迭代器对象,用于集合遍历(后面讲)1 2 3 4 5 6 7 8 9 10 11
   | @Test public void test4() {     Collection collection = new ArrayList();     collection.add("aa");     collection.add("bb");     collection.add(128);     Object[] array = collection.toArray();
      int i = collection.hashCode();     System.out.println(i); }
   | 
 
ArrayList集合和数组之间的转换
集合转换为数组,那么这个新的数组跟原集合就没有关系了,改变集合的值,不会影响到数组的值
但是如果是对数组使用Arrays.asList(Object[] obj)方法,来让一个数组转化为一个集合,此时的集合是只读(可以使用set,但是不能使用add和remove)的,且数组改变,会影响到集合的值
一个注意点
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | @Test public void test6() {          Integer[] arr = new Integer[]{1, 2, 3};     List<Integer> list = Arrays.asList(arr);     System.out.println(list);      System.out.println(list.size());
           int[] arr1 = new int[]{1, 2, 3};     List list1 = Arrays.asList(arr1);     System.out.println(list1);      System.out.println(list1.size()); }
   | 
 
小总结:向Collection中添加的元素,一般要求元素所属的类一定要重写equals,因为Collection中的相关方法(contains,remove)要调用equals()
iterator迭代器
用来遍历集合元素的
两个重要的方法
hashNext() 
next():指针下移,将下移以后集合位置上的元素返回 
搭配使用,可以用来遍历集合
1 2 3 4 5 6 7 8 9 10 11
   | @Test public void test1() {     Collection coll1 = new ArrayList();     coll1.add("AAA");     coll1.add("BBB");     coll1.add("CCC");     Iterator iterator = coll1.iterator();     while (iterator.hasNext()) {         System.out.println(iterator.next());     } }
   | 
 
增强for循环的原理就是使用的迭代器,实际上是语法糖,来简化迭代器的使用
List
List,用于存储有序的,可以重复的数据
List中的常用方法除了Collection中的方法外,还有一些其他的
因为List是有序的,进而就有索引,就会有一些针对索引的操作方法
remove(int index)删除指定索引的元素 
set(int index,Object obj)给指定索引设置值 
get(int index)获取指定索引的元素 
add(int index,Object obj)指定位置插入 
addAll(int index,Collection eles)插入多个 
indexOf(Object obj)返回obj在集合中首次出现的位置 
lastIndexOf(Object obj)返回obj在当前集合中末次出现的位置 
subList(int fromIndex,int toIndex)返回从fromIndex到toIndex-1位置的子集合 
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | @Test public void test1() {     List list = new ArrayList();     list.add("111");     list.add("222");     list.add(new Person("BB", 1));     list.forEach(System.out::println);
      System.out.println("===");
      list.add(1, "testInsert");     list.forEach(System.out::println);
  }
   | 
 
三个List实现类
- ArrayList:最常用的List实现类
 
- LinkedList:基于双向链表的结构
 
- Vector:List的一个古老的实现类
 
Set
Set:存储无序的,不可重复的数据
开发中,相较于List和Map,Set使用比较少
Set中的实现类
- HashSet:底层使用的是HashMap
 
- LinkedHashSet(继承的HashSet,在现有的结构上,又添加了一组双向链表,用于记录添加元素的先后顺序,即:我们可以按照添加元素的顺序实现遍历,便于频繁的查询操作)
 
- TreeSet:底层使用红黑树存储,可以按照添加的元素的指定的属性进行遍历
 
HashSet
- 无序性 != 随机性
这里的无序性,是指添加元素的位置是无序的,不像ArrayList一样是依次排列紧密的 
- 不可重复性
添加到Set中的元素是不能相同的,比较的标准:需要判断hashCode得到哈希值与equals得到的结果,哈希值相同且equals返回true才是相同 
如果Person没有重写hashCode方法,那么最下面的语句就会输出false,如果没有重写,调用的就是Object中的hashCode,Object 类的默认 hashCode 实现是为每个不同的对象实例返回不同的哈希码,即使这些对象在逻辑上是“相等的”(即它们的 equals 方法可能返回 true)。,这也就解释了为什么不重写hashCode,下面语句就返回false了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
   | @Test public void test1() {     Set set = new HashSet();
      set.add("AA");     set.add(123);     set.add("BB");     set.add("CC");     set.add("DD");     set.add(new Person("tom", 11));     for (Object o : set) {         System.out.println(o);     }
      System.out.println(set.contains(new Person("tom", 11))); }
   | 
 
小总结:添加到HashSet/LinkedHashSet中的元素的要求:要求元素所在的类要重写equals和hashCode方法
TreeSet
TreeSet的底层是红黑树,添加数据后,可以按照添加的元素的指定的大小顺序进行遍历
要求添加到TreeSet中的元素必须是同一个类型的对象,否则会报类型转换异常,因为TreeSet中会将其元素相互比较
1 2 3 4 5 6 7 8 9 10 11 12
   | @Test public void test1() {     TreeSet set = new TreeSet();     set.add("AA");     set.add("BB");     set.add("CC");     set.add("DD");     set.add(123);     for (Object o : set) {         System.out.println(o);     } }
   | 
 
TreeSet添加自定义的类,那自定义类要实现Comparable接口,或者TreeSet中传入一个Comparator对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
   |  @Override public int compareTo(Object o) {     if (o == this) {         return 0;     }     if (o instanceof User) {         User u = (User) o;         int result1 = Integer.compare(this.age, u.age);         if (result1 != 0) {                          return result1;         }         return this.name.compareTo(u.name);     }     throw new RuntimeException("类型错误"); }
 
  | 
 
如果这个compareTo方法中只比较了一个属性,那么在插入对象时,这个属性相同,就会判断为相同的属性,根本不会调用equals和hashCode方法,也就是说,在TreeSet中,判断相同的标准就是使用排序的方法了
下面是使用定制排序的方式,也就是不需要自定义类实现Comparable接口,而是给TreeMap传入一个Comparator接口的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | @Test public void test3() {     Comparator comparator = (o1, o2) -> {                  if (o1 instanceof User && o2 instanceof User) {             User u1 = (User) o1;             User u2 = (User) o2;             int result = u1.getName().compareTo(u2.getName());             if (result != 0) {                 return -result;             }             return Integer.compare(u1.getAge(), u2.getAge());         }         throw new RuntimeException("类型错误");     };          TreeSet set = new TreeSet(comparator);     set.add(new User("tom", 11));     set.add(new User("aom", 13));     set.add(new User("bom", 13));     set.add(new User("tom", 14));
      set.forEach(System.out::println); }
   | 
 
Set案例
定义方法如下:public static List duplicateList(List list)
- 参数List只存在Integer的对象
 
- 在List内去除重复数字值,尽量简单
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
   | public class TestDup {     public static void main(String[] args) {         List<Integer> list = new ArrayList<>();         list.add(1);         list.add(2);         list.add(2);         list.add(3);         List result = duplicateList(list);         list.forEach(System.out::println);         System.out.println("===");         result.forEach(System.out::println);     }
      
 
 
 
 
 
 
 
      public static List duplicateList(List<Integer> list) {         HashSet<Integer> hashSet = new HashSet<>(list);         List resultList = new ArrayList(hashSet);         return resultList;     }
  | 
 
Set案例二
编写一个程序,获取10个1-20的随机数,要求随机数不能重复,并把最终的随机数输出到控制台
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | public class TestRandom {     public static void main(String[] args) {         HashSet<Integer> set = new HashSet();         List<Integer> list = new ArrayList();         while (set.size() < 20) {             int a = (int) (Math.random() * 20) + 1;             list.add(a);             set.add(a);         }         set.forEach(System.out::println);         System.out.println("+++");         System.out.println(list.size());     } }
  | 
 
还有一个案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
   | public class HashSetDemo {     public static void main(String[] args) {         Set<Person> set = new HashSet();         Person p1 = new Person(1001, "AA");         Person p2 = new Person(1002, "BB");         set.add(p1);         set.add(p2);         System.out.println(set);
          p1.setName("CC");                  set.remove(p1);         System.out.println(set);
                   set.add(new Person(1001, "CC"));                  System.out.println(set);
                   set.add(new Person(1001, "AA"));                  System.out.println(set);     } }
  | 
 

Map接口
java.util.Map:存储一对一对数据
- HashMap,Map主要实现类,线程不安全的,可以添加null的key和value值
- LinkedHashMap,是HashMap的子类,在HashMap使用的数据结构的基础上,增加了双向链表,用于记录添加元素的先后顺序,可以按照添加的元素的指定的大小顺序进行遍历,对于频繁遍历的数据,可以优先考虑此结构
 
 
- TreeMap,底层使用红黑树存储,可以按照添加的key-value中的key元素的指定属性的大小顺序进行遍历
 
- Hashtable,Map的古老实现类,线程安全的,不可以添加null的key和value值
- Properties,其key和value都是String类型,常用来处理属性文件
 
 
HashMap
HashMap中的key用Set来存放,不允许重复,即同一个HashMap对象所对应的类,须重写hashCode()和equals方法(不重写,也能存,不过可能会有问题,参考Set)
HashMap中的一个key-value就构成了一个Entry,所以的entry彼此之间是不可重复的,无序的,所有的entry就构成了一个Set集合
常用方法
- 添加/修改
- Object put(key,value)将指定的key-value添加到(或修改)当前map对象中
 
- void putAll(Map m)将m中所有的key-value对存放到当前map中
 
 
- 删除操作
- Object remove(key):移除指定key的key-value对,并返回value
 
- void clear(),清空当面map中的所有数据
 
 
- 元素查询操作
- Object get(Object key),获取指定key对应的value
 
- containsKey(key)是否包含指定的key
 
- containsValue(Object value),是否包含指定的value
 
- int size()返回map中key-value对的个数
 
- isEmpty(),判断当前map是否为空
 
equals(Object obj):判断当前map和参数对象obj是否相等 
 
- 元视图操作的方法
- Set keySet():返回所有key构成的set集合
 
- Collection values()返回所有value构成的Collection集合
 
- Set entrySet(),返回所有key-value对构成的Set集合
 
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
   | @Test public void test3() {     Map<String, String> map = new LinkedHashMap<>();     map.put("11", "22");     map.put("110", "220");     map.put("12", "00");     map.put("00", "11");     Set<String> strings = map.keySet();     System.out.println(strings);     Collection<String> values = map.values();     System.out.println(values);     Set<Map.Entry<String, String>> entries = map.entrySet();     System.out.println(entries);     System.out.println("--");     for (Map.Entry<String, String> entry : entries) {         String key = entry.getKey();         String value = entry.getValue();         System.out.println("key=" + key + " value=" + value);     } }
  @Test public void test4() {          Map<String, String> map = new LinkedHashMap<>();     map.put("11", "22");     map.put("110", "220");     map.put("12", "00");     map.put("00", "11");
      for (String s : map.keySet()) {         String values = map.get(s);         System.out.println(values);     }
      System.out.println("===");
      String value = map.remove("00");     System.out.println(value);
      System.out.println("===");
      for (String s : map.keySet()) {         String values = map.get(s);         System.out.println(values);     }
      System.out.println("---");     map.put("11", "testUpdate");     System.out.println(map); }
   | 
 
TreeMap
可以按照添加的key-value中的key元素的指定属性的大小顺序进行遍历
需要考虑使用自然排序或定制排序,且TreeMap中添加的key必须是同一个类型的对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
   | @Test public void test2() {     Map<User, String> map = new TreeMap<>();     map.put(new User("tom", 11), "11");     map.put(new User("aom", 13), "22");     map.put(new User("tom", 13), "33");     map.put(new User("tom", 14), "44");     Set<Map.Entry<User, String>> entries = map.entrySet();     for (Map.Entry<User, String> entry : entries) {         System.out.println(entry);     } }
 
  @Test public void test3() {     Comparator comparator = (o1, o2) -> {         if (o1 instanceof User && o2 instanceof User) {             User u1 = (User) o1;             User u2 = (User) o2;                          int result1 = u1.getName().compareTo(u2.getName());             if (result1 != 0) {                 return result1;             }                          return u1.getAge() - u2.getAge();         }         throw new RuntimeException("类型错误");     };     Map<User, String> map = new TreeMap<>(comparator);     map.put(new User("tom", 11), "11");     map.put(new User("aom", 13), "22");     map.put(new User("tom", 13), "33");     map.put(new User("tom", 14), "44");     Set<Map.Entry<User, String>> entries = map.entrySet();     for (Map.Entry<User, String> entry : entries) {         System.out.println(entry);     } }
   | 
 
还有关于Properties的使用
1 2 3 4 5 6 7 8 9 10
   | @Test public void test1() throws IOException {     File file = new File("test.properties");     System.out.println(file.getAbsolutePath());     FileInputStream fis = new FileInputStream(file);     Properties properties = new Properties();     properties.load(fis);     System.out.println(properties.getProperty("name"));     System.out.println(properties.getProperty("password")); }
   | 
 
Collections工具类
Collections是一个操作Set,List和Map等集合的工具类
Collection和Collections的区别
Collection是集合框架中的用于存储一个一个元素的接口,又分为List和Set等子接口,而Collections是用于操作集合框架的工具类
常用api
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
   | @Test public void test1() {     List<Integer> list = new ArrayList<>();     list.add(1);     list.add(2);     list.add(3);     list.add(4);     list.add(5);
           Collections.shuffle(list);     System.out.println(list);
           Collections.sort(list);     System.out.println(list);
           Collections.sort(list, (o1, o2) -> -o1 - o2);     System.out.println(list);
           Collections.swap(list, 0, 4);     System.out.println(list); }
  @Test public void test2() {     List<String> list = Arrays.asList("AA", "BB", "CC", "DD");          String max = Collections.max(list);     System.out.println(max);
           String max1 = Collections.max(list, (o1, o2) -> -o1.compareTo(o2));     System.out.println(max1);
      String min = Collections.min(list);     System.out.println(min);
           String min1 = Collections.min(list, (o1, o2) -> -o1.compareTo(o2));     System.out.println(min1);
           int i = Collections.binarySearch(list, "AA");     System.out.println(i);
      int time = Collections.frequency(list, "AA");     System.out.println(time); }
  @Test public void test3() {     List<String> src = Arrays.asList("AA", "BB", "CC", "DD");     List<Object> dest = Arrays.asList(new Object[src.size()]);          Collections.copy(dest, src);     System.out.println(dest); }
  @Test public void test4() {          List<Integer> list = new ArrayList<>();     list.add(1);     list.add(2);
           List<Integer> unmodifiableList = Collections.unmodifiableList(list);     unmodifiableList.set(0, 1);     System.out.println(unmodifiableList); }
  @Test public void test5() {     List<Integer> list = new ArrayList<>();     list.add(1);     list.add(2);
           List<Integer> list1 = Collections.synchronizedList(list);     System.out.println(list1);
      Map<String, String> map = new HashMap<>();     map.put("11", "22");     Map<String, String> map1 = Collections.synchronizedMap(map);     System.out.println(map1); }
   | 
 
一个发牌案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
   | @Test public void test6() {     String[] num = {"A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"};     String[] color = {"方片", "梅花", "红桃", "黑桃"};
      ArrayList<String> poker = new ArrayList<>();     for (int i = 0; i < num.length; i++) {         for (int i1 = 0; i1 < color.length; i1++) {             poker.add(num[i] + color[i1]);         }     }
      poker.add("大王");     poker.add("小王");
           Collections.shuffle(poker);
      System.out.println(poker.size());
      List<String> one = new ArrayList<>();     List<String> two = new ArrayList<>();     List<String> three = new ArrayList<>();     List<String> last = new ArrayList<>();
      for (int i = 0; i < poker.size(); i++) {                  if (i >= poker.size() - 3) {             last.add(poker.get(i));         }         if (i % 3 == 0) {             one.add(poker.get(i));         } else if (i % 3 == 1) {             two.add(poker.get(i));         } else if (i % 3 == 2) {             three.add(poker.get(i));         }     }
      System.out.println(one);     System.out.println(two);     System.out.println(three);     System.out.println(last);
  }
   | 
 
Map练习题
其实是两道面试题,都是使用到了HashMap
查找排名最接近荣誉的排名
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
   | public class ClosestRankFinder {     public static int findClosestRank(Map<Integer, Integer> user) {                  int closestRank = -1;                  int minDifference = Integer.MAX_VALUE;
                   for (Map.Entry<Integer, Integer> entry : user.entrySet()) {             int currentRank = entry.getKey();             int currentHonor = entry.getValue();                          int difference = Math.abs(currentRank - currentHonor);
              if (difference <= minDifference) {                 minDifference = difference;                 closestRank = currentRank;             }         }
          return closestRank;     }
      public static void main(String[] args) {         Map<Integer, Integer> user = new HashMap<>();         user.put(1, 93);         user.put(10, 55);         user.put(15, 30);         user.put(20, 19);         user.put(23, 11);         user.put(30, 2);         int closestRank = findClosestRank(user);         System.out.println("排名最接近荣誉值的是:" + closestRank);     } }
  | 
 
判断str1字符串重排后是否能组成str2
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
   | @Test public void test3() {          String str1 = "kstedak";     String str2 = "steakk";
      Map<Character, Integer> map = new HashMap<>();     char[] charArray = str1.toCharArray();     for (char c : charArray) {                  map.put(c, map.getOrDefault(c, 0) + 1);     }
      for (char c : str2.toCharArray()) {         if (!map.containsKey(c) || map.get(c) == 0) {                          System.out.println(false);             return;         }         map.put(c, map.get(c) - 1);     }     System.out.println(true);
  }
   |