JavaEE - 11集合Collection
(1)Java集合框架概述
(1.1)数组的特点与缺点
- 集合、数组都是对多个数据进行存储操作的结构,简称Java容器。
- 此时的存储,主要指的是内存层面的存储,不涉及到持久化的存储(.txt, .jpg,.avi,数据库)
- 数组在存储多个数据方面的特点
- 一旦初始化以后,其长度就确定了。
- 数组一旦定义好,其元素的类型也确定了。只能操作指定类型的数据。如:String[] arr; int[] arr1; Object[] arr2;
- 数组在存储多个数据方面的缺点
- 一旦初始化以后,其长度就不可修改。
- 数组中提供的方法非常有限,对于添加、删除、插入数据等操作,非常不便,同时效率不高。
- 获取数组中实际元素的个数的需求,数组没有现成的属性或方法可用。
- 数组存储数据的特点: 有序、可重复。对于无序、不可重复的需求,不能满足。
- Java集合类可以存储数量不等的多个对象,也可用于保存具有映射关系的关联数组。
(1.2)集合使用场景
- 客户端: 将JSON对象或JSON数组转换为Java对象或Java对象构成的List
- 服务器端:将Java对象或Java对象构成的List 转换为JSON对象或JSON数组
(1.3)Java集合
Java集合可分为 Collection 和 Map 两种体系。
- Collection接口:单列数据,定义了存取一组对象的方法的集合
- List:元素有序、可重复的集合 ArrayList、LinkedList、Vector
- Set: 元素无序、不可重复的集合 HashSet、LinkedHashSet、 TreeSet
- SortedSet:无序、不可重复的,但是存储元素可以按照元素大小自动排序。
- Map接口:双列数据,保存具有映射关系"key-value对"的集合。HashMap、LinkedHashMap、TreeMap(SortedMap)、Hashtable、Properties
- 迭代器(Iterator、ListIterator)、对象排序接口(Comparable、Comparator)、容器工具类(Collections)
(2)Collection接口方法
- add(Object obj): 将元素obj添加到集合中
- int size(): 获取添加的元素个数
- addAll(Collection col): 将col集合中的元素添加到当前的集合中
- clear(): 清空集合元素
- isEmpty(): 判断当前集合是否为空
- contains(Object obj): 判断当前集合中是否包含obj元素
- containsAll(Collection col): 判断形参col中的所有元素是否都在当前集合中
- boolean remove(Object obj): 通过元素的equals方法判断是否是要删除的那个元素。只会删除找到的第一个元素。
- boolean removeAll(Collection col): 取当前集合的差集,从当前集合中移除形参col中的所有元素
- boolean retainAll(Collection c): 把交集的结果存在当前集合中,不影响集合c
- boolean equals(Object obj): 集合是否相等
- Object[] toArry(): 转换成对象数组
- hashCode(): 获取集合对象的哈希值
- iterator(): 返回迭代器对象,用于集合遍历
(2.1)add()、size()、addAll()、clear()、isEmpty()方法
@Test public void test1(){ Collection collection = new ArrayList(); collection.add("AA"); collection.add("BB"); collection.add(123); // 自动装箱 collection.add(new Date()); System.out.println(collection.size()); //4 Collection collection1 = new ArrayList(); collection1.add("DDD"); collection1.add(88); collection.addAll(collection1); System.out.println(collection.size()); //6 collection1.clear(); System.out.println(collection1.isEmpty()); //true }
(2.2) contains()方法
@Test public void test2(){ Collection coll = new ArrayList(); coll.add(123); coll.add(new String("Tom")); coll.add(false); coll.add(new Person("aaa",12)); System.out.println(coll); //[123, Tom, false, Person@621be5d1] boolean contains = coll.contains(123); System.out.println(contains); //true System.out.println(coll.contains(new String("Tom"))); //true Person p = new Person("bbb",34); coll.add(p); System.out.println(coll.contains(p)); //true System.out.println(coll.contains(new Person("bbb",34))); //false }
重写类的equals 和 hashCode方法
// 重写Person类的 equals 和 hashCode方法 @Override public boolean equals(Object o){ if(this == o) return true; if(o == null || getClass() != o.getClass()) return false; Person person = (Person) o; if(age != person.age) return false; return name != null ? name.equals(person.name) : person.name == null; } @Override public int hashCode() { int result = name != null ? name.hashCode() : 0; result = 31 * result + age; return result; }
System.out.println(coll.contains(new Person("bbb",34))); //true
重新 观察contains,对象比较过程
@Override public boolean equals(Object o){ System.out.println("Person equals()......"); ...... }
@Test public void test2(){ Collection coll = new ArrayList(); coll.add(123); coll.add(new String("Tom")); coll.add(false); coll.add(new Person("aaa",12)); System.out.println(coll); //[123, Tom, false, Person@621be5d1] // 在判断时调用obj对象所在类的equals()方法 System.out.println(coll.contains(new Person("aaa",12))); //true 从前往后,逐一比较,找到返回true,停止比较;找不到返回false。 }
[123, Tom, false, Person@2d8feb] Person equals()...... Person equals()...... Person equals()...... Person equals()...... true
向Collection接口的实现类的对象中添加数据obj时,要求obj所在类要重写equals()方法。
(2.3)containsAll()方法
@Test public void test3(){ Collection coll = new ArrayList(); coll.add(123); coll.add(new String("Tom")); coll.add(false); coll.add(new Person("aaa",12)); Collection coll01 = Arrays.asList(123,false,new Person("bbb",20)); System.out.println(coll.containsAll(coll01)); //false } //---------------------- Person equals()...... // new Person("bbb",20) 调用equals,一个个比较 Person equals()...... Person equals()...... Person equals()...... false
(2.4)remove()方法
@Test public void test3(){ Collection coll = new ArrayList(); coll.add(123); coll.add(new String("Tom")); coll.add(false); coll.add(new Person("aaa",12)); coll.remove(123); coll.remove(new Person("aaa",12)); coll.remove("Tom"); System.out.println(coll); // [false] } //--------------------- Person equals()...... Person equals()...... Person equals()...... [false]
(2.5)removeAll()方法
@Test public void test3(){ Collection coll = new ArrayList(); coll.add(123); coll.add(new String("Tom")); coll.add(false); coll.add(new Person("aaa",12)); Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("aaa",12)); Person p = new Person("bbb",34); coll02.add(p); System.out.println(coll02); coll.removeAll(coll02); System.out.println(coll); // [Tom, false] System.out.println(coll02); // [123, 456, Person@2d8feb, Person@2e0840] }
(2.6)retainAll()、equals()、hashCode()方法
@Test public void test4(){ Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("aaa",12)); coll02.add(new Person("bbb",34)); Collection coll03 = new ArrayList(); coll03.add(123); coll03.add(456); coll03.add(new Person("bbb",23)); System.out.println(coll02.retainAll(coll03)); // 输出6个Person equals() true; coll02的两个Person对象和coll03的每个比较,2*coll03.length System.out.println(coll02); //[123, 456] System.out.println(coll02.equals(coll03)); //false System.out.println(coll02.hashCode()); //5230 }
(2.7)集合和数组转换: toArray() / Arrays.asList()
@Test public void test5(){ Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("bbb",20)); //集合 -> 数组: toArray() Object[] arr = coll02.toArray(); for(int i = 0; i< arr.length; i++){ System.out.println(arr[i]); // 123 456 Person@2e0832 } // 数组 --> 集合 List<String> list = Arrays.asList(new String[]{"AA","BB","CC"}); System.out.println(list); // [AA, BB, CC] List<String> list1 = Arrays.asList("aa","cc","dd"); System.out.println(list1); // [aa, cc, dd] List arr1 = Arrays.asList(123,456); System.out.println(arr1); // [123, 456] , size=2 List arr2 = Arrays.asList(new int[]{123,456}); System.out.println(arr2); // [[I@621be5d1], size=1 List arr3 = Arrays.asList(new Integer[]{123,456}); System.out.println(arr3); // [123, 456], size=2 }
(3)Iterator迭代器接口
(3.1)iterator(): 返回Iterator接口的实例,用于遍历集合元素。
@Test public void test5(){ Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("bbb",20)); Iterator it = coll02.iterator(); // System.out.println(it.next()); // System.out.println(it.next()); // System.out.println(it.next()); // 当超出时,报异常:java.util.NoSuchElementException while(it.hasNext()){ // 迭代器推荐使用方法 System.out.println(it.next()); // 123 456 Person@2e0832 } }
(3.2)迭代器执行原理
- hasNext():判断是否还有下一个元素。
- next(): 指针下移; 将下移以后集合位置上的元素返回。
- Iterator it = coll02.iterator(); 指针初始位置在 集合第一个元素的上面
(3.3)使用Iterator接口遍历集合元素
- Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。
- GOF给迭代器模式的定义为:提供一种方法访问一个容器(container)对象中各个元素,而又不需暴露该对象的内部细节。
- Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,
- 那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象。
- Iterator仅用于遍历集合,Iterator本身并不提供承装对象的能力。如果需要创建Iterator对象,则必须有一个被迭代的集合。
- 集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
(3.4)错误使用Iterator方式
@Test public void test6(){ Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("bbb",20)); Iterator iterator = coll02.iterator(); while((iterator.next()) != null){ System.out.println(iterator.next()); // 456 报错java.util.NoSuchElementException } //集合对象每次调用iterator()都会得到一个新的迭代器对象,默认游标在集合第一个元素之前 while(coll02.iterator().hasNext()){ System.out.println(coll02.iterator().next()); // 123 死循环 } }
(3.5)remove()方法
- Iterator可以删除集合的元素,但是在遍历过程中通过迭代器对象的remove方法,不是集合对象的remove方法。
- 如果还未调用next()或者在上一次调用next方法之后已经调用了remove方法,再调用remove都会报illegalStateException。
@Test public void test6(){ Collection coll02 = new ArrayList(); coll02.add(123); coll02.add(456); coll02.add(new Person("bbb",20)); coll02.add("Tom"); Iterator iterator = coll02.iterator(); while (iterator.hasNext()){ Object obj = iterator.next(); if("Tom".equals(obj)){ iterator.remove(); } } System.out.println(coll02); // [123, 456, Person@2e0832] }
(3.6)使用foreach遍历集合元素
- Java5.0 提供了foreach 循环迭代访问Collection和数组。
- 遍历操作不需获取Collection或数组的长度,无需使用索引访问元素。
- 遍历集合的底层调用 Iterator完成操作。
- foreach 还可以用来遍历数组。
for(Object obj : coll02){ // for(集合元素的类型 局部变量 : 集合对象), 内部调用迭代器 System.out.println(obj); }
@Test public void test7(){ int[] arr = new int[]{1,2,3,4,5,67,8}; for(int i : arr){ System.out.println(i); } String[] arrs = new String[]{"AA","CC","DDD"}; for(int i = 0; i<arrs.length;i++){ System.out.println(arrs[i]); } // 增强for循环 for(String s : arrs){ System.out.println(s); } }
(3.7)Enumeration、ListIterator
- Enumeration接口作用与iterator接口相似,但只提供了遍历vector和HashTable类型集合元素的功能,不支持元素的移除操作。
- Enumeration速度是iterator的2倍,同时占用更少的内存。
- 但是,iterator远比enumeration安全,因为其他线程不能够修改正在被iterator遍历的集合里面的对象。同时,iterator允许调用者删除底层集合里面的元素。
- Iterator是ListIterator的父类接口
- Iterator是单列集合(Collection)公共取出容器中元素的方式,ListIterator是List集合的特有取出元素方式
- Iterator中具备的功能只有hashNext(),next(),remove();ListIterator中具备着对被遍历的元素进行增删查改的方法,可以对元素进行逆向遍历。
浙公网安备 33010602011771号