Java基础-集合
一、概述
Java 集合框架主要包括两种类型的容器,一种是集合(Collection),存储一个元素集合,另一种是图(Map),存储键/值对映射。
Collection是一组"对立"的元素,通常这些元素都服从某种规则
- List必须保持元素特定的顺序
- Set不能有重复元素且无序
- Queue保持一个队列(先进先出)的顺序
Map是一组成对的"键值对"对象
Collection和Map的区别在于容器中每个位置保存的元素个数:
- Collection 每个位置只能保存一个元素(对象)
- Map保存的是"键值对",就像一个小型数据库。我们可以通过"键"找到该键对应的"值"
集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含接口、实现类以及算法。具体框架如下图所示
Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框架位于java.util包中, 所以当使用集合框架的时候需要进行导包。
二、Collection
Collection是List、Set以及Quene的父接口,其中主要由以下方法组成。
这里集合的这些常用方法将会在之后的例子中具体呈现
集合的遍历
集合的遍历主要使用iterator进行遍历,下面举一个具体的例子吧!
public static void main(String[] args) {
Collection m = new ArrayList();
m.add("zjj");
m.add("mabuli");
Iterator iterator = m.iterator();//获取迭代器
while ((iterator.hasNext())){//集合中是否存在下个元素
System.out.println(iterator.next());//打印集合中下个元素
}
}
最后输出结果
注意一下,iterator.next()获取的元素时object类型,需要强制类型转换,这里因为原类型为String类型,所以在输出时可以不考虑强转。
ps:在我做毕业设计的时候出现了一个小Bug,集合元素在迭代的过程中不可以Remove方法,如果使用的话会抛出异常,比如下个例子。
public static void main(String[] args) {
Collection m = new ArrayList();
m.add("zjj");
m.add("mabuli");
Iterator iterator = m.iterator();//获取迭代器
while ((iterator.hasNext())){//集合中是否存在下个元素
if(iterator.next().equals("mabuli")){
m.remove("mabuli");
}
}
}
正确的做法是通过迭代器中的remove方法删除mabuli
public static void main(String[] args) {
Collection m = new ArrayList();
m.add("zjj");
m.add("mabuli");
Iterator iterator = m.iterator();//获取迭代器
while ((iterator.hasNext())){//集合中是否存在下个元素
if(iterator.next().equals("mabuli")){
iterator.remove();
}
}
Iterator iterator1 = m.iterator();
while (iterator1.hasNext()){
System.out.println(iterator1.next());
}
}
2.1 Set集合
Set集合类似一个罐子,程序可以把多个对象丢进set集合,但是set集合通常不能记住元素的添加顺序,所以其不能添加重复元素,其余的与Collection大致相同。
我们目前常用的主要分为以下几种
HashSet
其具有以下特点:
- 不能保证元素排列顺序
- 线程不同步
- 元素之可以为空
元素的存储位置主要是通过hashcode的值来确定,如果两个元素hashcode以及equal值全相同,则他们会被当做成一个对象。当我们使用hashset时,尽量不要去修改参与hashcode、equals计算的实例变量,否则hashset可能会无法操作这些元素。
LinkedHashSet
LinkedHashSet与传统的hashset不同点是其以链表来维护元素的次序,这样使元素看起来是以插入的顺序保存的,因为它要维护元素的相关顺序,其性能比其父类HashSet低一些,但在迭代访问时会有很好的性能。
public class SetTest1 {
public static void main(String[] args) {
LinkedHashSet<Object> dirtyLily = new LinkedHashSet<>();
dirtyLily.add("cueb");
dirtyLily.add("pku");
dirtyLily.add("bnu");
System.out.println(dirtyLily);
dirtyLily.remove("cueb");
dirtyLily.add("cueb");
System.out.println(dirtyLily);
}
}
我们可以发现,最后输出是按照元素的添加顺序来的。
TreeSet
TreeSet是SortedSet接口的实现类,其元素一直可以处于排序的状态,其还提供了如下的额外方法。
其与HashSet不同的是,其实通过红黑树的数据结构来存储集合元素,其支持两种排序方法,自然排序以及定制排序,一般来说选择自然排序。
这里需要注意的是,当往treeset中添加元素时,元素所在的类应该已经实现了comparable接口,并且Set中所有类型应该是相同的。下面给大家举一个具体例子。
我先定义了一个空的jjj类,他没有实现comparable接口,当向treeset中添加相关类时则会抛出异常。
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Object> cc = new TreeSet<>();
cc.add(new jjj());
}
}
报出以下异常
当其中添加两个不同类型的值时也会报相关异常。
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Object> cc = new TreeSet<>();
cc.add("aaa");
cc.add(new Date());
}
}
其中报出相同异常
在treeset中会通过compareTo比较两个对象是否相等,如果其返回0,则TreeSet会认为他们相等的。与HashSet一样,treeset中也最好不要去修改可变对象的值。
2.2 List集合
List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。
List集合中除了可以使用Collection接口中的全部方法,因为它属于有序集合,所以也添加了一些其他带索引值的方法。
具体各位可以在以下博文查看,这里我就不赘述了
https://blog.csdn.net/qq_37959072/article/details/89217610
在List中,判断两个元素是否相等只需要判断他们的equal方法是否返回true。
List中除了可以使用Iterator迭代元素,还添加了一个listIterator,他增加了一个hasprevious和previous方法,可以遍历前面的元素。
public static void main(String[] args) {
java.util.List list = new ArrayList();
list.add("dirty");
list.add("smallLily");
list.add("aimin");
ListIterator listIterator = list.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
System.out.println("==============");
while (listIterator.hasPrevious()){
System.out.println(listIterator.previous());
}
}
最后输出
List两个实现类Arraylist和Vector的显著区别就是,Arraylist线程不安全,Vector线程安全(但是效率低),Vector中提供模拟栈的子类stack。
2.3 Queue集合
queue在java中是模拟队列的一种类,队列主要是先进先出的线性表,Queue接口中定义了如下方法。
在其中比较常用的实现类是PriorityQueue,这种实现类它与平常的队列不同,他是按照队列中元素的大小进行排序,所以说他违背了队列的“先进先出”的思想,在调用poll方法时,他将会按照从小到大的顺序把元素移出。
Deque接口
Deque接口是Queue的子接口,它代表一个双端的队列,具体各位可以看一下的文章
https://blog.csdn.net/u011630575/article/details/79923132
之前我们讲到的LinkedList以及ArrayDeque都实现了Deque接口,它们也可以模拟成栈或队列使用。
三、map集合
Map用于保存具有映射关系的数据,所以说Map集合里一般保存两组值,一组保存key、一组保存value,map中的key不许重复,map中的所有key可以看做是组成了一个set集合(不重复、无序),里面的所有value可以看成一个list。它主要具有如下方法:
先试试:
public static void main(String[] args) {
HashMap<Object, Object> jj = new HashMap<>();
jj.put("1","jj");
jj.put("2","jjj");
jj.put("3","jjjj");
for (java.util.Map.Entry<Object, Object> entry : jj.entrySet()) {
System.out.println(entry.getKey());
System.out.println(entry.getValue());
System.out.println("==================");
}
}
最后输出如下结果
HashMap和HashTable
这俩都是map接口的典型实现类,其中绝大多数部分都是相同的,但是也有如下两点不同:
- hashmap线程不安全,hashtable现成安全
- hashtable不能用null当keyvalue,hashmap可以的
LinkedHashMap
其使用双向链表维护key-value的次序,其性能比hashmap略低,但是在迭代访问时效率会更高一些。
Treemap
与TreeSet相同,在map中也有类似的TreeMap实现类,在其存储的过程中会根据key对相应节点进行排序。
其判断两个key相等的标准也是来判断其compareto方法是否返回0,如果返回0就是相等的
Collections集合工具类
在java中提供了一个操作Set、list、map等集合的工具类collections,他可以对元素进行排序、查询、修改等操作。
其中主要包括以下方法:
- Shuffle(element):洗牌方法,将当前集合内的数据进行随机排序。
- Reverse(element):逆序排序,对当前集合的元素按照相反的顺序进行排序
- Sort(element):对当前集合进行升序排序,实现Comparable接口的类,只能使用一种排序方案,这种方案叫作“自然比较”方案。
当然他其中包含一个比较厉害的方法,就是synchronizedXxx,他可以直接将线程不安全的实现类(HashSet等)直接包装成线程安全的,所以说通过它就可以直接获得Set list以及map的线程安全版本。