1.集合
在内存层面需要针对于多个数据进行存储。此时可以考虑的容器有:数组、集合类。
- 数组存储多个数据方面的特点:
- 数组一旦初始化,其长度就是确定的。
- 数组中的多个元素是依次紧密排列的,有序的,可重复的。
- 数组一旦初始完成,其元素的类型就是确定的。不是此类型的元素无法添加到该数组中。
- 数组中元素的类型既可以是基本数据类型,也可以是引用数据类型。
- 数组存储多个数据方面的弊端:
- 数组一旦初始化,其长度就不可变。
- 数组中存储数据特点的单一性。对于无序的、不可重复的场景的多个数据就无能为力。
- 数组中可用的方法、属性都极少。具体的需求,都需要自己来组织相关的代码逻辑。
- 针对于数组中元素的删除、插入操作,性能较差。
1.1 Java集合框架体系
- java.util.Collection:存储一个一个的数据。
- 子接口List:存储有序的、可重复的数据(”动态“数组)。ArrayList(主要实现类)、LinkedList、Vector。
- 子接口Set:存储无序的、不可重复的数据。HashSet、LinkedHashSet、TreeSet。
- java.util.Map:存储一对一对的数据。
- HashMap(主要实现类)、LinkedHashMap、TreeMap、Hashtable、Properties。
1.2 Collection接口及方法
JDK 不提供此接口的任何直接实现,而是提供更具体的子接口(如:Set 和 List)去实现。Collection 接口是 List 和 Set 接口的父接口,该接口里定义的方法既可用于操作 Set 集合,也可用于操作 List 集合。
1.2.1 常用方法
- add(Object obj):添加元素对象到当前集合中。
- addAll(Collection other):添加 other 集合中的所有元素对象到当前集合中,即 this = this ∪ other。
- int size():获取当前集合中实际存储的元素个数。
- boolean isEmpty():判断当前集合是否为空集合。
- boolean contains(Object obj):判断当前集合中是否存在一个与 obj 对象 equals 返回 true 的元素。
- boolean containsAll(Collection coll):判断 coll 集合中的元素是否在当前集合中都存在。即 coll 集合是否是当前集合的“子集”。
- boolean equals(Object obj):判断当前集合与 obj 是否相等。
- void clear():清空集合元素。
- boolean remove(Object obj) :从当前集合中删除第一个找到的与 obj 对象 equals 返回 true 的元素。
- boolean removeAll(Collection coll):从当前集合中删除所有与 coll 集合中相同的元素。即 this = this - this ∩ coll。
- boolean retainAll(Collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与 coll 集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即 this = this ∩ coll。
- Object[] toArray():返回包含当前集合中所有元素的数组。
- hashCode():获取集合对象的哈希值。
- iterator():返回迭代器对象,用于集合遍历。
1.2.2 集合与数组的相互转换
- 集合转数组:toArray()。
- 数组转集合:调用Arrays的静态方法asList(Object … objs)。
向Collection中添加元素时,要求元素所属的类一定要重写equals()方法。因为Collection中的相关方法在使用时,要调用元素所在类的equals()方法。
1.3 迭代器接口(Iterator)及方法
- 在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK 专门提供了一个接口 java.util.Iterator。Iterator 接口也是 Java 集合中的一员,但它与Collection、Map 接口有所不同。
- Collection 接口与 Map 接口主要用于存储元素。
- Iterator,被称为迭代器接口,本身并不提供存储对象的能力,主要用于遍历 Collection 中的元素。
- Collection 接口继承了 java.lang.Iterable 接口,该接口有一个 iterator()方法,那么所有实现了 Collection 接口的集合类都有一个 iterator()方法,用以返回一个实现了 Iterator接口的对象。
- public Iterator iterator(): 获取集合对应的迭代器,用来遍历集合中的元素的。
- 集合对象每次调用 iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前。
1.3.1 常用方法
- public E next():返回迭代的下一个元素。作用1是将指针下移;作用2是将下移以后集合位置上的元素返回。
- public boolean hasNext():如果仍有元素可以迭代,则返回 true。
- 注意:在调用 it.next()方法之前必须要调用 it.hasNext()进行检测。若不调用,且下一条记录无效,直接调用 it.next()会抛出 NoSuchElementException 异常。
Iterator iterator = coll.iterator(); while(iterator.hasNext()){System.out.println(iterator.next());}
1.3.2 foreach循环
foreach 循环(也称增强 for 循环)是 JDK5.0 中定义的一个高级 for 循环,专门用来遍历数组和集合的。
foreach 循环的语法格式:
for(要遍历的集合或数组元素的类型 临时变量 : 要遍历的集合或数组变量){//操作临时变量的输出操作
}@Testpublic void test1(){Collection coll = new ArrayList();coll.add("AA");coll.add("BB");coll.add(128);coll.add(new String("张三"));for (Object obj:coll) {System.out.println(obj);}}
说明:
- 针对于集合来讲,增强for循环的底层仍然使用的是迭代器。
- 增强for循环的执行过程中,是将集合或数组中的元素依次赋值给临时变量。注意,循环体中对临时变量的修改,可能不会导致原有集合或数组中元素的修改。
1.4 List接口及方法
List接口用于存储有序的、可以重复的数据。可以使用List替代数组。
1.4.1 常用方法
- add(Object obj):添加元素对象到当前集合中。
- addAll(Collection other):添加 other 集合中的所有元素对象到当前集合中,即 this = this ∪ other。
- int size():获取当前集合中实际存储的元素个数。
- boolean isEmpty():判断当前集合是否为空集合。
- boolean contains(Object obj):判断当前集合中是否存在一个与 obj 对象 equals 返回 true 的元素。
- boolean containsAll(Collection coll):判断 coll 集合中的元素是否在当前集合中都存在。即 coll 集合是否是当前集合的“子集”。
- boolean equals(Object obj):判断当前集合与 obj 是否相等。
- void clear():清空集合元素。
- boolean remove(Object obj) :从当前集合中删除第一个找到的与 obj 对象 equals 返回 true 的元素。
- boolean removeAll(Collection coll):从当前集合中删除所有与 coll 集合中相同的元素。即 this = this - this ∩ coll。
- boolean retainAll(Collection coll):从当前集合中删除两个集合中不同的元素,使得当前集合仅保留与 coll 集合中的元素相同的元素,即当前集合中仅保留两个集合的交集,即 this = this ∩ coll。
- Object[] toArray():返回包含当前集合中所有元素的数组。
- hashCode():获取集合对象的哈希值。
- iterator():返回迭代器对象,用于集合遍历。
- void add(int index, Object ele):在 index 位置插入 ele 元素。
- boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来。
- Object get(int index):获取指定 index 位置的元素。
- List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合。
- int indexOf(Object obj):返回 obj 在集合中首次出现的位置。
- int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置。
- Object remove(int index):移除指定 index 位置的元素,并返回此元素。
- Object set(int index, Object ele):设置指定 index 位置的元素为ele。
1.4.2 List 接口的实现类
- ArrayList:List的主要实现类,线程不安全但效率高;底层使用Object[]数组存储。
- Vector:List的古老实现类,线程安全但效率低;底层使用Object[]数组存储。
- LinkedList:底层使用双向链表的方式进行存储。
package p156;import java.util.ArrayList;
import java.util.Scanner;public class StudentTest {public static void main(String[] args) {Scanner sc = new Scanner(System.in);ArrayList list = new ArrayList();System.out.println("请输入学生信息:");while (true){System.out.println("1:继续输入,0:结束录入");int selection = sc.nextInt();if (selection == 0){break;}System.out.print("请输入学生姓名:");String name = sc.next();System.out.print("请输入学生年龄:");int age = sc.nextInt();Student s = new Student(name, age);list.add(s);}for (Object arr:list) {System.out.println(arr.toString());}sc.close();}
}
package p156;import java.util.ArrayList;
import java.util.Collection;public class ListTest {public static void main(String[] args) {ArrayList<Object> list = new ArrayList<>();for (int i = 0; i < 30; i++) {list.add((char) (Math.random() * (122 - 97 + 1) + 97) + "");}int aCount = listTest(list, "a");int bCount = listTest(list, "b");int cCount = listTest(list, "c");int xCount = listTest(list, "x");System.out.println(aCount);System.out.println(bCount);System.out.println(cCount);System.out.println(xCount);}public static int listTest(Collection list, String s){int count = 0;for (Object obj :list) {if (s.equals(obj)){count++;}}return count;}
}
1.5 Set接口及方法
1.5.1 介绍
- Set 接口是 Collection 的子接口,Set 接口相较于 Collection 接口没有提供额外的方法。
- Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。
- Set 集合支持的遍历方式和 Collection 集合一样:foreach 和 Iterator。
- Set 的常用实现类有:HashSet、TreeSet、LinkedHashSet。
1.5.2 HashSet
- HashSet 是 Set 接口的主要实现类,大多数时候使用 Set 集合时都使用这个实现类。
- HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存储、查找、删除性能。
- HashSet 具有以下特点:
- 不能保证元素的排列顺序。
- HashSet 不是线程安全的。
- 集合元素可以是 null。
- HashSet 集合判断两个元素相等的标准:两个对象通过 hashCode() 方法得到的哈希值相等,并且两个对象的 equals()方法返回值为 true。
- 对于存放在 Set 容器中的对象,对应的类一定要重写 hashCode()和 equals(Object obj)方法,以实现对象相等规则。即:“相等的对象必须具有相等的散列码”。
- HashSet 集合中元素的无序性,不等同于随机性。这里的无序性与元素的添加位置有关。具体来说:我们在添加每一个元素到数组中时,具体的存储位置是由元素的hashCode()调用后返回的 hash 值决定的。导致在数组中每个元素不是依次紧密存放的,表现出一定的无序性。
1.5.3 LinkedHashSet
- LinkedHashSet 是 HashSet 的子类,不允许集合元素重复。
- LinkedHashSet 根据元素的 hashCode 值来决定元素的存储位置,但它同时使用双向链表维护元素的次序,这使得元素看起来是以添加顺序保存的。
- LinkedHashSet 插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。
1.5.4 TreeSet
- TreeSet 是 SortedSet 接口的实现类,TreeSet 可以按照添加的元素的指定的属性的大小顺序进行遍历。
- TreeSet 底层使用红黑树结构存储数据。
- TreeSet 特点:不允许重复、实现排序(自然排序或定制排序)。
- 自然排序:默认情况下,TreeSet 采用自然排序(TreeSet 会调用集合元素的 compareTo(Object obj) 方法来比较元素之间的大小关系,然后将集合元素按升序(默认情况)排列)。
- 如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现Comparable 接口。
- 实现 Comparable 的类必须实现compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。
- 定制排序:如果元素所属的类没有实现 Comparable 接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过 Comparator 接口来实现。需要重写compare(T o1,T o2)方法。
- 利用 int compare(T o1,T o2)方法,比较 o1 和 o2 的大小:如果方法返回正整数,则表示 o1 大于 o2;如果返回 0,表示相等;返回负整数,表示 o1 小于 o2。
- 要实现定制排序,需要将实现 Comparator 接口的实例作为形参传递给 TreeSet 的构造器。
- 因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。
- 对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过compareTo(Object obj) 或 compare(Object o1,Object o2)方法比较返回值。返回值为 0,则认为两个对象相等。
/*** 将0-20之间的随机数放入集合中,要求不能出现重复元素*/
public class Exer02 {public static void main(String[] args) {HashSet set = new HashSet();while (set.size() < 10) {int random = (int) (Math.random() * (10 - 1 + 1) + 1);set.add(random);}Iterator iterator = set.iterator();while (iterator.hasNext()){System.out.println(iterator.next());}}
}
/*** 去除列表中重复的元素,仅保留一个即可*/public class Exer01 {public static void main(String[] args) {ArrayList list = new ArrayList();list.add(34);list.add(34);list.add(34);list.add(24);list.add(24);list.add(44);list.add(44);list.add(44);List newList = duplicateList(list);System.out.println(newList);}public static List duplicateList(List list){HashSet set = new HashSet(list);ArrayList list1 = new ArrayList(set);return list1;}
}
1.6 Map接口及方法
1.6.1 Map及其实现类对比
- HashMap:主要实现类,线程不安全但效率高,可以添加null的key和value值,底层使用数组+单向链表+红黑树结构存储(JDK8)。
- Hashtable:古老实现类,线程安全但效率低,不可以添加null的key和value值,底层使用数组+单向链表结构存储(JDK8)。
- LinkedHashMap:是HashMap的子类,在HashMap使用的数据结构的基础上,增加了一对双向链表,用于记录添加的元素的先后顺序,进而在遍历时可以按照添加的顺序显示。在开发中,对于频繁的遍历操作,建议使用此类。
- TreeMap:底层使用红黑树存储,可以按照添加的key-value中的key元素的指定的属性大小顺序进行遍历。需要考虑自然排序和定制排序。
- Properties:是Hashtable的子类,其key和value都是String类型,常用来处理属性文件。
1.6.2 HashMap中元素的特点
- HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key构成一个Set集合。key所在的类要重写hashCode()和equals()方法。
- HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成了一个Collection集合。value所在的类要重写equals()方法。
- HashMap中的一个key-value构成一个entry。HashMap中所有的entry彼此之间是不可重复的、无序的。所有的entry构成了一个Set集合。
1.6.3 Map中的常用方法
- 添加、修改操作:
- Object put(Object key,Object value):将指定 key-value 添加到(或修改)当前map 对象中。
- void putAll(Map m):将 m 中的所有 key-value 对存放到当前 map 中。
- 删除操作:
- Object remove(Object key):移除指定 key 的 key-value 对,并返回 value。
- void clear():清空当前 map 中的所有数据。
- 元素查询的操作:
- Object get(Object key):获取指定 key 对应的 value。
- boolean containsKey(Object key):是否包含指定的 key。
- boolean containsValue(Object value):是否包含指定的 value。
- int size():返回 map 中 key-value 对的个数。
- boolean isEmpty():判断当前 map 是否为空。
- boolean equals(Object obj):判断当前 map 和参数对象 obj 是否相等。
- 元视图操作的方法:
- Set keySet():返回所有 key 构成的 Set 集合。
- Collection values():返回所有 value 构成的 Collection 集合。
- Set entrySet():返回所有 key-value 对构成的 Set 集合。
1.6.4 TreeMap的使用
- 底层使用红黑树存储。
- 可以按照添加的key-value中的key元素的指定属性大小顺序进行遍历。
- 考虑使用自然排序和定制排序。
- 要求向TreeMap中添加的的key必须是同一个类型的对象。
1.6.5 Hashtable与Properties的使用
Properties:是Hashtable的子类,其key和value都是String类型,常用来处理属性文件。
package p161;import java.util.*;public class SingerTest {public static void main(String[] args) {HashMap singers = new HashMap();String singer1 = "周杰伦";ArrayList songs1 = new ArrayList();songs1.add("夜曲");songs1.add("晴天");songs1.add("七里香");songs1.add("青花瓷");singers.put(singer1,songs1);Set entrySet = singers.entrySet();Iterator iterator = entrySet.iterator();while (iterator.hasNext()){Map.Entry entry = (Map.Entry) iterator.next();System.out.println("歌手:"+entry.getKey());System.out.println("歌曲有:"+entry.getValue());}}
}
1.7 Collections工具类
Collections是一个操作Set、List和Map等集合的工具类。
1.7.1 常用方法
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作,还提供了对集合对象设置不可变、对集合对象实现同步控制等方法(均为static 方法)。
- 排序操作:
- reverse(List):反转 List 中元素的顺序。
- shuffle(List):对 List 集合元素进行随机排序。
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序。
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序。
- swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换。
- 查找:
- Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素。
- Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素。
- Object min(Collection):根据元素的自然顺序,返回给定集合中的最小元素。
- Object min(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最小元素。
- int binarySearch(List list,T key):在 List 集合中查找某个元素的下标,但是 List 的元素必须是 T 或 T 的子类对象,而且必须是可比较大小的,即支持自然排序的。而且集合也事先必须是有序的,否则结果不确定。
- int binarySearch(List list,T key,Comparator c):在 List 集合中查找某个元素的下标,但是List 的元素必须是 T 或 T 的子类对象,而且集合也事先必须是按照 c 比较器规则进行排序过的,否则结果不确定。
- int frequency(Collection c,Object o):返回指定集合中指定元素的出现次数。
- 复制、替换:
- void copy(List dest,List src):将 src 中的内容复制到 dest 中。
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值。
- 提供了多个unmodifiableXxx()方法,该方法返回指定 Xxx 的不可修改的视图。
- 添加:
- boolean addAll(Collection c,T… elements):将所有指定元素添加到指定 collection 中。
- 同步:
- Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全问题。