文章目录
Collection接口及迭代器
Collection接口继承Iterable接口。
Collection接口有两个方法,add()和iterator();
add():向实现接口的集合中添加元素;
iterator():所有实现Iterable接口的集合都可以通过该方法来遍历集合中的元素;
/***
* ArrayList是Collection接口的一个实现
* **/
List<String> list = new ArrayList<>();
list.add("123");
list.add("ABC");
/***
* 方式一:iterator()获得迭代器遍历
* **/
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
/***
*方式二:for遍历方式
* **/
for (String str : list
) {
System.out.println(str);
}
泛型方法的使用
从Collection接口和Iterable接口可以看出,这两个都是泛型接口,这两个接口实现的集合可以存放任意数据类型的元素,极大提高了代码的复用性。下面例子简单介绍了这种思想,判断任何类型集合中是否有某个元素。
/**
* ArrayList
* **/
List<String> list = new ArrayList<>();
list.add("123");
list.add("ABC");
/**
* ArrayDeque
* **/
Queue<String> deque = new ArrayDeque<>();
deque.add("123");
deque.add("ABC");
boolean flag = GenericParadigmTest.isEqual(list, "123");
System.out.println(flag);
boolean flag2 = GenericParadigmTest.isEqual(deque, 1234);
System.out.println(flag2);
}
/**
* 泛型方法的使用:判断某个元素在集合中是否存在
***/
public static <E> boolean isEqual(Collection<E> es, Object o) {
for (E e : es) {
if (e.equals(o)) {
return true;
} else {
return false;
}
}
return false;
}
集合基本接口和实现
Java中集合的基本接口有Collection和Map。一个是单元素(Value)集合,另一个是键值对(Key-Value)集合。
继承Collection的接口有List、Set、Queue。
List
List实现的集合是有序可重复元素集合。List的常见实现:ArrayList、LinkedList。
ArrayList
ArrayList封装了一个动态数组,在连续的地址中存放者对象的引用,可自动扩容。查找元素速度块,但插入和删除元素的速度慢,因为每次插入和删除元素需要将后面的所有元素移动来保持有序性。
LinkedList
LinkedList是一个链表结构,每一个节点存放着下一个节点的引用,节点间存放的内存空间不是连续的。查询元素的时候慢,需要从头节点开始遍历,但查询和删除元素快,只需要更改目标节点前后的引用即可。
LinkedList.add()方法只能往链表尾部添加元素。
要想往链表任何位置添加元素或者修改元素,可以使用ListIterator.listIterator()方法。这个方法可以通过迭代器往链表任何位置添加元素。
/**
* LinkedList.add()方法只能往链表尾部添加元素
* ***/
List<Integer> staff = new LinkedList<>();
staff.add(1);
staff.add(2);
staff.add(3);
Iterator<Integer> iterator = staff.iterator();
System.out.println("LinkedList.add()方法往链表尾部添加元素:" + staff);
/**
*ListIterator.listIterator()方法可以通过迭代器往链表任何位置添加元素
* **/
List<Integer> staff2 = new LinkedList<>();
staff2.add(12);
staff2.add(23);
ListIterator<Integer> listIterator = staff2.listIterator();
listIterator.next();
listIterator.add(34);
System.out.println("ListIterator.add()方法可以通过迭代器往链表任何位置添加元素:" + staff2);
listIterator.next();
listIterator.add(11111);
System.out.println("ListIterator.set()方法可以通过迭代器修改链表任何位置元素:" + staff2);
/**
* 后序遍历
* **/
while (listIterator.hasPrevious()) {
System.out.println(listIterator.previous());
}
LinkedList.add()方法往链表尾部添加元素:[1, 2, 3]
ListIterator.add()方法可以通过迭代器往链表任何位置添加元素:[12, 34, 23]
ListIterator.set()方法可以通过迭代器修改链表任何位置元素:[12, 34, 23, 11111]
11111 23 34 12
ListIterator接口和Iterable接口的区别
在上面我们使用到了ListIterator,而ListIterator接口继承Iterable接口。
他们之间的区别如下:
ListIterator可以往List中添加元素和修改元素,而Iterable不能;
ListIterator和Iterable都可以顺序遍历集合,但ListIterator还可以倒叙遍历集合;
ListIterator和Iterable都可以删除元素。
如果需要频繁进行插入和删除操作的情况可以使用链表结构存储数据,如下:
public static void main(String[] args) {
List<String> a = new LinkedList<>();
a.add("amy");
a.add("carl");
a.add("erica");
System.out.println(a);
List<String> b = new LinkedList<>();
b.add("bob");
b.add("doug");
b.add("frances");
b.add("gloria");
System.out.println(b);
/***
* 将链表b的元素合并到链表a
* **/
ListIterator<String> aIter = a.listIterator();
Iterator<String> bIter = b.iterator();
while (bIter.hasNext()) {
if (aIter.hasNext())
aIter.next();
aIter.add(bIter.next());
}
System.out.println(a);
/***
* 将链表b的元素删除
* **/
while (bIter.hasNext()) {
bIter.next();
while (bIter.hasNext()){
bIter.next();
bIter.remove();
}
}
System.out.println(b);
/**
* 从a中移除所有b的元素
* ***/
a.removeAll(b);
System.out.println(a);
}
[amy, carl, erica]
[bob, doug, frances, gloria]
[amy, bob, carl, doug, erica, frances, gloria]
[bob, doug, frances, gloria]
[amy, carl, erica]
Set
Set实现的集合是不可重复集合.
Set接口常见的实现有:HashSet、TreeSet。
HashSet
HashSet是一个散列集,插入元素时随机分布在散列表中,使用迭代器遍历散列表时元素的顺序也是随机的,但不允许重复元素插入。
TreeSet
TreeSet是一个树集,按任意顺序插入元素,在树上会自动进行排序,遍历时会按照排序好的顺序进行输出。
例如,从TreeSet输入三个元素,再遍历输出。
public static void main(String[] args) {
Set<String> sorts = new TreeSet<>();
sorts.add("huan");
sorts.add("bao");
sorts.add("long");
for (String s : sorts) {
System.out.println(s);
}
}
bao
huan
long
使用树集需要元素对象实现Comparable接口并实现其中的compareTo()方法或者自己实现一个Comparator比较器。
例如,定义一个Item类来实现Comparable接口时遍历集合元素按compareTo()方法的逻辑来进行元素排序;
定义Comparator比较器时遍历集合元素按比较器的逻辑来进行元素排序。
package com.teasir.collection.set;
import java.util.Objects;
public class Item implements Comparable<Item> {
private String descripton;
private int number;
public Item(String descripton, int number) {
this.descripton = descripton;
this.number = number;
}
public String getDescripton() {
return descripton;
}
public void setDescripton(String descripton) {
this.descripton = descripton;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Item item = (Item) o;
return number == item.number &&
descripton.equals(item.descripton);
}
@Override
public int hashCode() {
return Objects.hash(descripton, number);
}
@Override
public String toString() {
return "Item{" +
"descripton='" + descripton + '\'' +
", number=" + number +
'}';
}
@Override
public int compareTo(Item o) {
int diff = Integer.compare(number, o.getNumber());
return diff != 0 ? diff : descripton.compareTo(o.getDescripton());
}
}
package com.teasir.collection.set;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
/**
* 按照Item默认的排序方式排序
* **/
Set<Item> items = new TreeSet<>();
items.add(new Item("huan", 1224));
items.add(new Item("bao", 4544));
items.add(new Item("long", 345));
System.out.println(items);
/**
* 定义一个Comparator对元素进行排序
* **/
Set<Item> itemSelf=new TreeSet<>(Comparator.comparing(Item::getDescripton));
itemSelf.addAll(items);
System.out.println(itemSelf);
}
}
[Item{descripton='long', number=345}, Item{descripton='huan', number=1224}, Item{descripton='bao', number=4544}]
[Item{descripton='bao', number=4544}, Item{descripton='huan', number=1224}, Item{descripton='long', number=345}]
Queue
Queue接口实现的是一个队列结构,存储元素的特点是先进先出。队列的常见两种实现:ArrayDeque、LinkedList、PriorityQueue。
ArrayDeque和LinkedList
循环数组ArrayDeque效率比链表LinkedList高;
循环数组ArrayDeque是一个有界集合,如果存放的元素无限,则使用链表实现队列更合适
ArrayDeque和LinkedList都可以实现双端队列,都可以从队列头和尾插入和删除元素。
PriorityQueue
PriorityQueue为优先队列,跟之前提到的TreeSet概念大同小异,会对插入队列的元素按一定的规则进行排序,遍历和删除的时候都会按照排序好的顺序进行相应操作。
例如,使用优先队列实现按时间顺序将最久远的数据删除功能,但这些数据插入队列时的顺序并不是按照时间来插入的。
package com.teasir.collection.Queue;
import java.time.LocalDate;
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueTest {
public static void main(String[] args) {
Queue<LocalDate> prtQueue=new PriorityQueue<>();
prtQueue.add(LocalDate.of(2022,1,12));
prtQueue.add(LocalDate.of(2022,2,23));
prtQueue.add(LocalDate.of(2022,1,06));
System.out.println(prtQueue);
while (!prtQueue.isEmpty()){
System.out.println(prtQueue.remove());
}
}
}
[2022-01-06, 2022-02-23, 2022-01-12]
2022-01-06
2022-01-12
2022-02-23
Map
Map接口常见的实现有HashMap、TreeMap、LinkedHashMap、HashTable、ConcurrentHashMap。
TreeMap
TreeMap跟之前的TreeSet、PriorityQueue会将插入元素按一定的逻辑进行排序。
HashTable和ConcurrentHashMap
HashTable跟HashMap差不多,但他是线程安全的,现在基本不会使用HashTable,如果需要考虑线程安全需要使用ConcurrentHashMap,而不是HashTable。
LinkedHashMap
LinkedHashMap会记住插入元素的顺序,按照插入元素的顺序进行排序。
例如,往LinkedHashMap按一定顺序插入元素,遍历时发现顺序与插入顺序相同。
package com.teasir.collection.map;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapTest {
public static void main(String[] args) {
Map<String,String> staff=new LinkedHashMap();
staff.put("long","243");
staff.put("huan","22343");
staff.put("bao","2443");
/**
*key的遍历
* */
for(String key:staff.keySet()){
System.out.println(key);
}
/**
* key和value的遍历
* **/
for(Map.Entry entry:staff.entrySet()){
System.out.println(entry.getKey()+":"+entry.getValue());
}
}
}
long
huan
bao
long:243
huan:22343
bao:2443
LinkedHashMap可以按照"最少使用原则"来设计一个缓存器,缓存里面只存储最近有使用过的元素,如果超过了规定的元素,缓存会自动删除,只保留符合条件的元素。
例如,设计一个只缓存10条数据的缓存器,多余元素从缓存中清除。
package com.teasir.collection.map;
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapTest {
public static void main(String[] args) {
Map<String, String> staff = new LinkedHashMap<String, String>(16, 0.75F, true) {
protected boolean removeEldestEntry(Map.Entry<String, String> entry) {
return size() > 10;
}
};
staff.put("long", "243");
staff.put("huan", "22343");
staff.put("bao", "2443");
staff.put("longg", "243");
staff.put("huann", "22343");
staff.put("baoo", "2443");
staff.put("long2", "243");
staff.put("huan2", "22343");
staff.put("bao2", "2443");
staff.put("longg2", "243");
staff.put("huann2", "22343");
staff.put("baoo2", "2443");
staff.put("long3", "243");
staff.put("huan4", "22343");
staff.put("bao5", "2443");
staff.put("longg6", "243");
staff.put("bo", "超出元素");
/**
* key和value的遍历
* **/
for (Map.Entry entry : staff.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
huan2:22343
bao2:2443
longg2:243
huann2:22343
baoo2:2443
long3:243
huan4:22343
bao5:2443
longg6:243
bo:超出元素
总结
1、Collection接口继承Iterable接口,每一个实现Collection接口的集合都可以通过迭代器遍历元素。
2、Java中集合的基本接口有Collection和Map。
3、继承Collection的接口有List、Set、Queue。
4、List的常见实现:ArrayList、LinkedList。
ArrayList底层实现是数组,元素在内存中的位置是连续的,可以通过索引快速查询指定位置的元素,但修改和删除元素时,需要移动该操作元素后续的所有元素;
LinkedList的底层实现是链表,元素在内存中的位置是不连续的,元素之间通过指针间的引用连接,查询时需要从头节后开始遍历,修改和删除元素时修改节点的引用即可。
5、Set接口常见的实现有:HashSet、TreeSet。
6、队列的常见两种实现:ArrayDeque、LinkedList、PriorityQueue。
ArrayDeque和LinkedList都可以实现双端队列。
7、Map接口常见的实现有HashMap、TreeMap、LinkedHashMap、HashTable、ConcurrentHashMap。
HashTable跟HashMap差不多,但他是线程安全的,现在基本不会使用HashTable,如果需要考虑线程安全需要使用ConcurrentHashMap,而不是HashTable。
LinkedHashMap会记住插入元素的顺序,按照插入元素的顺序进行排序。
8、TreeMap、TreeSet、PriorityQueue会将插入元素按一定的逻辑进行排序。这三个集合存储的元素必须实现Comparable接口或者实现一个Comparator比较器。
参考文章
https://blog.csdn.net/qq_18433441/article/details/78221810
https://www.cnblogs.com/wxd0108/p/5906618.htmlb
https://blog.csdn.net/weixin_39241397/article/details/79687789