在认识集合之前,先思考一个问题:
在编程中常常需要集中存放多个数据,虽然可以使用数组来存放保存,但数组的长度不可变化,一旦初始化了数组长度,这个数组就是不可变的,那么如何存储动态变化的数据呢?
你想到了吗?没错,这就是接下来要介绍的知识:集合。
为了保存不确定的数据以及保存具有映射关系的数据,java提供了集合类。
数组 | 集合 |
---|---|
存储基本数据类型或引用数据类型 | 只存储引用数据类型 |
存储长度固定 | 存储动态可变 |
本文主要就Set、List、Map的部分子类,通过举例的方式进行对常用的集合进行说明、归纳、总结。
Set就类似于一个罐子,程序可以依次把多个对象丢进去,不记它的顺序。
特点:无序、无下标、不可以重复。
Set集合与Collection基本相同,没有提供额外的方法,只是行为有些不同。(不允许包含相同的元素)
Set方法
返回值 | 方法 | 描述 |
---|---|---|
boolean | add(E e) | 如果指定的元素不存在,则将其指定的元素添加(可选操作)。 |
boolean | addAll(Collection extends E> c) | 将指定集合中的所有元素添加到此集合(如果尚未存在)(可选操作)。 |
void | clear() | 从此集合中删除所有元素(可选操作)。 |
boolean | contains(Object o) | 如果此集合包含指定的元素,则返回 true 。 |
boolean | containsAll(Collection> c) | 返回 true如果此集合包含所有指定集合的元素。 |
boolean | equals(Object o) | 将指定的对象与此集合进行比较以实现相等。 |
int | hashCode() | 返回此集合的哈希码值。 |
boolean | isEmpty() | 如果此集合不包含元素,则返回 true 。 |
Iterator | iterator() | 返回此集合中元素的迭代器。 |
boolean | remove(Object o) | 如果存在,则从该集合中删除指定的元素(可选操作)。 |
boolean | removeAll(Collection> c) | 从此集合中删除指定集合中包含的所有元素(可选操作)。 |
boolean | retainAll(Collection> c) | 仅保留该集合中包含在指定集合中的元素(可选操作)。 |
int | size() | 返回此集合中的元素数(其基数)。 |
default | Spliterator spliterator() | 在此集合中的元素上创建一个 Spliterator 。 |
Object[] | toArray() | 返回一个包含此集合中所有元素的数组。 |
(1)哈希表边存放的是哈希值。HashSet存储元素的顺序并不是按照存入时的顺序(和List显然不同) 是按照哈希值来存的所以取数据也是按照哈希值取得。
(2)具有很好的存取和查找性能。
(3)HashSet是不同步的。如果有多个线程同时访问一个HashSet,必须通过代码来保证其同步。
(4)集合元素值可以是NULL 。
具体存储描述:
当向HashSet集合中存入一个元素时,HashSet会调用该对象的HashCode()方法来得到该对象的HashCode值,然后根据该HashCode值决定该对象在HashSet的存储位置。如果有2个元素通过equals()方法比较返回true,但它们的HashCode()方法返回值不相等,HashSet将会把它们存在不同的位置,依然可以添加成功。
举个栗子:
public class SetDemo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("小红");
set.add("小华");
set.add("小紫");
set.add("小紫");
System.out.println("元素个数为:" + set.size());
System.out.println("原始列表:" + set.toString());
// 遍历(Set无角标方法)
System.out.println("--------for-each遍历-------");
for (String s: set) {
System.out.println(s);
}
System.out.println("--------迭代器遍历-------");
Iterator<String> iterator=set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
System.out.println("--------集合是否包含某个对象--------");
System.out.println("输入你要查询的对象:");
Scanner scanner=new Scanner(System.in);
String s=scanner.next();
if (set.contains(s)) {
System.out.println("此集合包含"+s);
}
else{
System.out.println("此集合不包含"+s);
}
}
}
结果
元素个数为:3
原始列表:[皮尺, 憨憨, 白白]
--------for-each遍历-------
皮尺
憨憨
白白
--------迭代器遍历-------
皮尺
憨憨
白白
--------集合是否包含某个对象--------
输入你要查询的对象:
白白
此集合包含白白
(or)
输入你要查询的对象:
黑黑
此集合不包含黑黑
(1)List集合是允许使用重复元素。
(2)默认按照元素的添加顺序设置元素的索引。
(3)有序、有下标、可重复。
List实现了Collection里的所有方法。
同时添加了一些根据索引来操作集合元素的方法。
返回值 | 方法 | 描述 |
---|---|---|
boolean | add(E e) | 将指定的元素追加到此列表的末尾(可选操作)。 |
void | add(int index, E element) | 将指定的元素插入此列表中的指定位置(可选操作)。 |
boolean | addAll(Collection extends E> c) | 按指定集合的迭代器(可选操作)返回的顺序将指定集合中的所有元素附加到此列表的末尾。 |
boolean | addAll(int index, Collection extends E> c) | 将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。 |
void | clear() | 从此列表中删除所有元素(可选操作)。 |
boolean | contains(Object o) | 如果此列表包含指定的元素,则返回 true 。 |
boolean | containsAll(Collection> c) | 如果此列表包含指定 集合的所有元素,则返回true。 |
boolean | equals(Object o) | 将指定的对象与此列表进行比较以获得相等性。 |
E | get(int index) | 返回此列表中指定位置的元素。 |
int | hashCode() | 返回此列表的哈希码值。 |
int | indexOf(Object o) | 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 |
boolean | isEmpty() | 如果此列表不包含元素,则返回 true 。 |
Iterator | iterator() | 以正确的顺序返回该列表中的元素的迭代器。 |
int | lastIndexOf(Object o) | 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。 |
ListIterator | listIterator() | 返回列表中的列表迭代器(按适当的顺序)。 |
ListIterator | listIterator(int index) | 从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。 |
E | remove(int index) | 删除该列表中指定位置的元素(可选操作)。 |
boolean | remove(Object o) | 从列表中删除指定元素的第一个出现(如果存在)(可选操作)。 |
boolean | removeAll(Collection> c) | 从此列表中删除包含在指定集合中的所有元素(可选操作)。 |
default void | replaceAll(UnaryOperator operator) | 将该列表的每个元素替换为将该运算符应用于该元素的结果。 |
boolean | retainAll(Collection> c) | 仅保留此列表中包含在指定集合中的元素(可选操作)。 |
E | set(int index, E element) | 用指定的元素(可选操作)替换此列表中指定位置的元素。 |
int | size() | 返回此列表中的元素数。 |
default void | sort(Comparator super E> c) | 使用随附的 Comparator排序此列表来比较元素。 |
default Spliterator | spliterator() | 在此列表中的元素上创建一个Spliterator 。 |
List | subList(int fromIndex, int toIndex) | 返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。 |
Object[] | toArray() | 以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。 |
(1)ArrayList是连续的、基于动态数组的数据结构。
(2)ArrayList的查询与修改较快。
(3)封装了一个动态的、允许再分配的Object[]数组。
(4)其线程不安全。当多个线程访问同一个ArrayList时,若有同时超过一个线程修改集合,必须手动保证该集合的同步性。
(5)若想把它变成安全的,需要用到Collections工具类。
举个栗子:
public class CollectionDemo2 {
public static void main(String[] args) {
Collection collection = new ArrayList();
Student s1 = new Student("小凰", 21);
Student s2 = new Student("小驴", 20);
Student s3 = new Student("小箐", 20);
Student s4 = new Student("小婪", 19);
Student s5 = new Student("小姊", 18);
collection.add(s1);
collection.add(s2);
collection.add(s3);
collection.add(s4);
collection.add(s5);
System.out.println("列表元素个数为:" + collection.size());
// 删除
// collection.remove(s1);
// System.out.println("删除后列表元素个数为:" + collection.size());
// 不会删除上述列表中相应的学生信息
// collection.remove(new Student("小箐", 20));
// 遍历
System.out.println("--------for-each遍历-------");
for (Object student : collection) {
Student s = (Student) student;
System.out.println(student.toString());
}
System.out.println("--------迭代器遍历-------");
Iterator iterator=collection.iterator();
while (iterator.hasNext()){
Object obj=(Object) iterator.next();
System.out.println(obj);
}
}
}
结果
列表元素个数为:5
--------for-each遍历-------
Student{name=‘小凰’, age=21}
Student{name=‘小驴’, age=20}
Student{name=‘小箐’, age=20}
Student{name=‘小婪’, age=19}
Student{name=‘小姊’, age=18}
--------迭代器遍历-------
Student{name=‘小凰’, age=21}
Student{name=‘小驴’, age=20}
Student{name=‘小箐’, age=20}
Student{name=‘小婪’, age=19}
Student{name=‘小姊’, age=18}
//使用集合工具类
public class CollectionsDSemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(20);
list.add(12);
list.add(28);
list.add(90);
list.add(43);
// sort排序
System.out.println("排序之前:" + list.toString());
Collections.sort(list);
System.out.println("排序之后" + list.toString());
// binarySearch二分查找
int i1 = Collections.binarySearch(list, 20);
System.out.println(i1);
int i2 = Collections.binarySearch(list, 12);
System.out.println(i2);
int i3 = Collections.binarySearch(list, 28);
System.out.println(i3);
int i4 = Collections.binarySearch(list, 90);
System.out.println(i4);
int i5 = Collections.binarySearch(list, 43);
System.out.println(i5);
// copy赋值
List<Integer> dest = new ArrayList<>();
for (int k = 0; k < list.size(); k++) {
dest.add(0);
}
Collections.copy(dest, list);
System.out.println("copy赋值后"+dest.toString());
// reserve反转
Collections.reverse(list);
System.out.println("反转之后:" + list);
// shuffle打乱
Collections.shuffle(list);
System.out.println("打乱之后:" + list);
// 补充:list转成数组
System.out.println("-----list转成数组------");
Integer[] arr = list.toArray(new Integer[0]);
System.out.println(arr.length);
System.out.println(Arrays.toString(arr));
// 补充:数组转成集合
String[] names = {
"张三", "李四", "赵七"};
List<Integer> list1 = Arrays.asList(arr);
// 不允许删除\添加,集合是一个受限集合
// list1.add("王五");
list1.remove("张三");
System.out.println(list1);
}
}
结果
排序之前:[20, 12, 28, 90, 43]
排序之后[12, 20, 28, 43, 90]
1
0
2
4
3
copy赋值后[12, 20, 28, 43, 90]
反转之后:[90, 43, 28, 20, 12]
打乱之后:[28, 43, 90, 20, 12]
-----list转成数组------
5
[28, 43, 90, 20, 12]
[28, 43, 90, 20, 12]
(1)LinkedList是基于链表的数据结构,它是一个双向链表。
(2)LinkedList的增加与查询较快。
(3)实现了Deque接口,可被当作双端队列来使用。
举个栗子:
public class LinkedListDemo1 {
public static void main(String[] args) {
LinkedList linkedList = new LinkedList<>();
Student s1 = new Student("小凰", 21);
Student s2 = new Student("小驴", 20);
Student s3 = new Student("小箐", 20);
Student s4 = new Student("小婪", 19);
Student s5 = new Student("小姊", 18);
linkedList.add(s1);
linkedList.add(s2);
linkedList.add(s3);
linkedList.add(s4);
linkedList.add(s5);
System.out.println("列表元素个数为:" + linkedList.size());
System.out.println(linkedList.toString());
linkedList.remove(new Student("小凰", 21));//重写equals了
// linkedList.remove(s1);
System.out.println("删除之后:" + linkedList.size());
System.out.println(linkedList.toString());
// 遍历
System.out.println("-----------for -----------");
for (int i=0;i<linkedList.size();i++){
System.out.println(linkedList.get(i));//返回此列表中指定位置的元素
}
System.out.println("--------for-each遍历-------");
for (Object obj: linkedList) {
Student s=(Student)obj;
System.out.println(obj);
// System.out.println(s.toString());
}
System.out.println("--------迭代器遍历-------");
Iterator iterator=linkedList.iterator();
while(iterator.hasNext()){
Student s=(Student)iterator.next();
System.out.println(s.toString());
}
ListIterator listIterator=linkedList.listIterator();
System.out.println("--------列表迭代器:前-后-------");
while(listIterator.hasNext()){
System.out.println(listIterator.nextIndex()+":"+listIterator.next());
}
// hasPrevious方法必须在上面的hasNext方法用完后才可以使用.不然直接用,不会生效.
System.out.println("--------列表迭代器:后-前-------");
while(listIterator.hasPrevious()){
System.out.println(listIterator.previousIndex()+":"+listIterator.previous());
}
}
}
结果
列表元素个数为:5
[Student{name=‘小凰’, age=21}, Student{name=‘小驴’, age=20}, Student{name=‘小箐’, age=20}, Student{name=‘小婪’, age=19}, Student{name=‘小姊’, age=18}]
删除之后:4
[Student{name=‘小驴’, age=20}, Student{name=‘小箐’, age=20}, Student{name=‘小婪’, age=19}, Student{name=‘小姊’, age=18}]
-----------for -----------
Student{name=‘小驴’, age=20}
Student{name=‘小箐’, age=20}
Student{name=‘小婪’, age=19}
Student{name=‘小姊’, age=18}
--------for-each遍历-------
Student{name=‘小驴’, age=20}
Student{name=‘小箐’, age=20}
Student{name=‘小婪’, age=19}
Student{name=‘小姊’, age=18}
--------迭代器遍历-------
Student{name=‘小驴’, age=20}
Student{name=‘小箐’, age=20}
Student{name=‘小婪’, age=19}
Student{name=‘小姊’, age=18}
--------列表迭代器:前-后-------
0:Student{name=‘小驴’, age=20}
1:Student{name=‘小箐’, age=20}
2:Student{name=‘小婪’, age=19}
3:Student{name=‘小姊’, age=18}
--------列表迭代器:后-前-------
3:Student{name=‘小姊’, age=18}
2:Student{name=‘小婪’, age=19}
1:Student{name=‘小箐’, age=20}
0:Student{name=‘小驴’, age=20}
(1)Map用于保存具有映射关系的数据,因此Map集合里保存着两组值(key,value)
(2)key不可以重复,value可以重复。
返回值 | 方法 | 描述 |
---|---|---|
void | clear() | 从该地图中删除所有的映射(可选操作)。 |
default V | compute(K key, BiFunction super K,? super V,? extends V> remappingFunction) | 尝试计算指定键的映射及其当前映射的值(如果没有当前映射, null )。 |
default V | computeIfAbsent(K key, Function super K,? extends V> mappingFunction) | 如果指定的键尚未与值相关联(或映射到 null ),则尝试使用给定的映射函数计算其值,并将其输入到此映射中,除非 null 。 |
default V | computeIfPresent(K key, BiFunction super K,? super V,? extends V> remappingFunction) | 如果指定的密钥的值存在且非空,则尝试计算给定密钥及其当前映射值的新映射。 |
boolean | containsKey(Object key) | 如果此映射包含指定键的映射,则返回 true 。 |
boolean | containsValue(Object value) | 如果此地图将一个或多个键映射到指定的值,则返回 true 。 |
Set |
entrySet() | 返回此地图中包含的映射的Set视图。 |
boolean | equals(Object o) | 将指定的对象与此映射进行比较以获得相等性。 |
default void | forEach(BiConsumer super K,? super V> action) | 对此映射中的每个条目执行给定的操作,直到所有条目都被处理或操作引发异常。 |
V | get(Object key) | 返回到指定键所映射的值,或 null如果此映射包含该键的映射。 |
default V | getOrDefault(Object key, V defaultValue) | 返回到指定键所映射的值,或 defaultValue如果此映射包含该键的映射。 |
int | hashCode() | 返回此地图的哈希码值。 |
boolean | isEmpty() | 如果此地图不包含键值映射,则返回 true 。 |
Set | keySet() | 返回此地图中包含的键的Set视图。 |
default V | merge(K key, V value, BiFunction super V,? super V,? extends V> remappingFunction) | 如果指定的键尚未与值相关联或与null相关联,则将其与给定的非空值相关联。 |
V | put(K key, V value) | 将指定的值与该映射中的指定键相关联(可选操作)。 |
void | putAll(Map extends K,? extends V> m) | 将指定地图的所有映射复制到此映射(可选操作)。 |
default V | putIfAbsent(K key, V value) | 如果指定的键尚未与某个值相关联(或映射到 null )将其与给定值相关联并返回 null ,否则返回当前值。 |
V | remove(Object key) | 如果存在(从可选的操作),从该地图中删除一个键的映射。 |
default boolean | remove(Object key, Object value) | 仅当指定的密钥当前映射到指定的值时删除该条目。 |
default V | replace(K key, V value) | 只有当目标映射到某个值时,才能替换指定键的条目。 |
default boolean | replace(K key, V oldValue, V newValue) | 仅当当前映射到指定的值时,才能替换指定键的条目。 |
default void | replaceAll(BiFunction super K,? super V,? extends V> function) | 将每个条目的值替换为对该条目调用给定函数的结果,直到所有条目都被处理或该函数抛出异常。 |
int | size() | 返回此地图中键值映射的数量。 |
Collection | values() | 返回此地图中包含的值的Collection视图。 |
(1)HashMap通过hashcode对其内容进行快速查找
(2)HashMap是基于哈希表的Map实现的。
(3)允许使用null键和null值。
(4)所有已实现的接口: Serializable, Cloneable, Map
(5)HashMap:适用于在Map中插入、删除和定位元素。
(6)非线程安全。
下面主要通过linkedHashMap来举个栗子:
public class MapDemo {
public static void main(String[] args) {
LinkedHashMap<String,String> linkedHashMap=new LinkedHashMap();
linkedHashMap.put("0","荔枝");
linkedHashMap.put("2","苹果");
linkedHashMap.put("3","葡萄");
linkedHashMap.put("5","芒果");
linkedHashMap.put("1","香蕉");
//
System.out.println("--------Iterator遍历-------");
Iterator it = linkedHashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
}
System.out.println("--------for-each--------");
// Set> entries = map.entrySet();
for (String key:linkedHashMap.keySet()) {
System.out.println("key= "+key+" and value= "+linkedHashMap.get(key));
}
for (Map.Entry<String, String> entry:linkedHashMap.entrySet()) {
String value = entry.getValue();
String key = entry.getKey();
System.out.println("key="+key+"\tvalue="+value);
}
}
}
(1)一个有序的key-value集合,它是通过红黑树实现的。
(2)继承于AbstractMap,所以它是一个Map,即一个key-value集合。
(3)实现了NavigableMap接口,意味着它支持一系列的导航方法。比如返回有序的key集合。
(4)实现了Cloneable接口,意味着它能被克隆。
(5)实现了java.io.Serializable接口,意味着它支持序列化。
(6)Treemap:适用于按自然顺序或自定义顺序遍历键(key)。
(7)非线程安全。
举个简单栗子:
public class MapDemo2 {
public static void main(String[] args) {
TreeMap<String,String> treeMap=new TreeMap();
treeMap.put("0","荔枝");
treeMap.put("2","苹果");
treeMap.put("3","葡萄");
treeMap.put("5","芒果");
treeMap.put("1","香蕉");
//
Iterator it = treeMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry entry = (Map.Entry) it.next();
System.out.println("key:" + entry.getKey() + " value:" + entry.getValue());
}
}
}
结果
key:0 value:荔枝
key:1 value:香蕉
key:2 value:苹果
key:3 value:葡萄
key:5 value:芒果
本文上述已经描述了许多的内容与特点等,可以具体参观一下上述描述或者下述博客吖~
https://blog.csdn.net/u012102104/article/details/79235938
本篇文章主要是认识并了解一下集合。上述附属了一些简单的使用例子。在后续的学习中会不断更新吖~
欢迎三连@_@