详解Java集合

196 阅读9分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

详解Java集合

1、什么是集合

集合是存放一组数据的容器,同时能够对数据进行存储,查询,操作等。 我们也听说过“数组”,同样的,“数组”也可以进行数据的存储,查询和操作。

集合与数组两者的区别就是

(1)数组长度不可改变,而集合的长度可以
随需求变动
(2)数组中可以存放基本类型数据和对象,
而集合只能存储对象

2、类图

只画出主要的类图,因为画太多就显得太乱了。

classDiagram
      Collection <|.. List
      Collection <|.. Set
      Iterator <|-- Collection
      Listiterator <|.. List
      Iterator<|..Listiterator
     List<|--LinkedList
     List<|--ArrayList
     Set<|--TreeSet
     Set<|--LinkedHashSet
     Set<|--HashSet
     Map<|--HashMap
      Map<|--LinkedHashMap
       Map<|--TreeMap
     class HashSet{
     }
     class LinkedHashSet{
     }
        class TreeSet{
     }
	class ArrayList{
	}
	class LinkedList{
	}

	class HashMap{
	}
	class LinkedHashMap{
	}
	class TreeMap{
	}
      class Listiterator{
      <<interface>>
      }
   class Collection {
	<<interface>>
   }
   class Map{
   	<<interface>>
   }
      class  Iterator{
      <<interface>>
      }
      class Set{
            <<interface>>
      }
      class List{
      <<interface>>
      }    
      

3、主要接口和实现类

(1)Collection接口

Collection接口是继承自Iterator接口的子接口,同时也是List和Set以及Queue(图中没画出来)的父接口。Collection接口定义了多种方法:

1)boolean add(Object ob) 将对象ob添加进集合 2)int size() 返回元素的数量


import java.util.Collection;

public class CollectionTest {
	public static void main(String args[]){
	Collection c1=	new  ArrayList();
	Collection c2=new  ArrayList();
	//为c2添加数据
	c2.add("JavaJL");
	c2.add(new Boolean(true));
	c2.add(2);//在这里用到了自动装箱,向集合添加的2不是int类型,而是int的包装类Integer类型
	//返回元素的数量
	System.out.println("c2中共有:"+c2.size()+"个元素");
	System.out.println(c2);
	}
}
	
c2中共有:3个元素
原始的c2集合:[JavaJL, true, 2]

3)boolean remove(Object ob) 将对象ob从集合中删除

import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest {
	public static void main(String args[]){
	Collection c2=new  ArrayList();
	//为c2添加数据
	c2.add("JavaJL");
	c2.add(new Boolean(true));
	c2.add(2);//在这里用到了自动装箱,向集合添加的2不是int类型,而是int的包装类Integer类型
	//返回元素的数量
	System.out.println("c2中共有:"+c2.size()+"个元素");
	System.out.println("原始的c2集合:"+c2);
	c2.remove(true);
	
	System.out.println("删除true元素后的c2集合:"+c2);
	}
}

c2中共有:3个元素
原始的c2集合:[JavaJL, true, 2]
删除true元素后的c2集合:[JavaJL, 2]

4)boolean addAll(Collection c)将集合c中所有元素添加到该集合 5)void removeAll(Collection c) 从集合中删除集合c中的所有元素 6)void retainAll(Collection c)从集合中删除集合c中没有的元素

import java.util.ArrayList;
import java.util.Collection;

public class CollectionTest {
	public static void main(String args[]){
	Collection c1=	new  ArrayList();
	Collection c2=new  ArrayList();
	c2.add("JavaJL");
	c2.add(new Boolean(true));
	c2.add(2);
//	将集合c2中所有元素添加到该集合c1
	c1.addAll(c2);
	c1.add("one");
	c2.add("two");
	System.out.println("c1集合的元素:"+c1);
	System.out.println("c2集合的元素:"+c2);
	
//	从集合c1中删除集合c2中的所有元素
	c1.removeAll(c2);

	System.out.println("从集合中删除集合c2中的所有元素");
	System.out.println("c1集合的元素:"+c1);
	System.out.println("c2集合的元素:"+c2);
	
//	从c2中删除没有在c1中的元素
	c1.add("JavaJL");
	c2.retainAll(c1);
	System.out.println("从集合c2中删除集合c1中没有的元素");
	System.out.println("c1集合的元素:"+c1);
	System.out.println("c2集合的元素:"+c2);
	}
}

结果为:

c1集合的元素:[JavaJL, true, 2, one]
c2集合的元素:[JavaJL, true, 2, two]
从集合中删除集合c2中的所有元素
c1集合的元素:[one]
c2集合的元素:[JavaJL, true, 2, two]
从集合c2中删除集合c1中没有的元素
c1集合的元素:[one, JavaJL]
c2集合的元素:[JavaJL]

7boolean isEmpty() 判断集合是否为空
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest {
	public static void main(String args[]){
	Collection c1=new  ArrayList();
	c1.add("JavaJL");
	c1.add(new Boolean(true));
	c1.add(2);
	System.out.println(c1.isEmpty());
	}
}

结果为:false

8)Iterator iterator()返回迭代器

在Iterator接口介绍

(2)Iterator接口

Iterator中定义的方法:

1)boolean hasNext():判断是否还有元素,有就返回True,否则返回False 2)Object next():返回下一个元素并将指针指向下一个元素 3) void remove()删除指针指向的元素

使用Collection中的iterator()方法可以获得Iterator对象,iterator()方法能以迭代方式逐个访问集合中的元素。如果集合中的元素没有排序,则iterator()方法遍历元素的顺序是随机的,并不一定能和加入集合的顺序一样。

import java.util.*;
public class IteratorTest{
public static void main(String args[]){
Collection c=new ArrayList();
c.add(23);
c.add(false);
c.add("JavaJL");
//获取迭代器
Iterator it=c.iterator();
//使用迭代器遍历集合
while(it.hasNext()){
System.out.print(it.next()+" ");
		}
	}
}

结果为:

23 false JavaJL 

1)解析hasNext和next方法

先看一段代码和结果

import java.util.*;
public class IteratorTest{
public static void main(String args[]){
Collection c=new ArrayList();
c.add(23);
c.add(false);
c.add("JavaJL");

Iterator it=c.iterator();
while(it.hasNext()){
System.out.println(c);
System.out.println(it.next()+" ");
it.remove();
		}
	}
}

结果为:

[23, false, JavaJL]
23 
[false, JavaJL]
false 
[JavaJL]
JavaJL 

可以想象使用迭代器的集合的最前方有一个指针p,他指向集合的第一个元素的前一个元素 在这里插入图片描述

当调用迭代器的hasNext()方法时,它会去查看p所指向元素的下一个元素是否存在,若存在,则返回true,否则,返回false。 当调用迭代器的next()方法时,指针p会向下移动,并指向下一个元素。此时,当调用迭代器的remove()方法时,会删除掉p指针所指向的元素。

在这里插入图片描述

(3)Set接口

Set集合是一种最简单的集合,存放于集合中的对象不安特定的方式排序,只是简单的将对象加入到集合。对集合中存放对象的访问和操作是通过对象的引用进行的,所以Set集合中的元素不可重复。 Set接口有3个实现类分别是HashSetLinkedHashSetTreeSet

1)HashSet

HashSet按哈希算法来存储集合中的元素,具有很好的存取性能。当HashSet向集合中加入一个元素时,会调用对象的hashCode()方法获取Hash码,后根据Hash码来计算出对象在集合中的位置。

tpis:HashSet不能保证迭代的顺序和插入的顺序保持一致

import java.util.*;
public class IteratorTest{
public static void main(String args[]){
Set set=new HashSet();
set.add("one");
set.add(23);
set.add(true);
set.add("two");
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(it.next()+" ");
it.remove();
		}
	}
}

结果为:

one 
23 
two 
true 

2)LinkedHashSet

与HashSet相比LinkedHashSet可以按照插入的顺序进行迭代。LinkedHashSet删除元素后会去掉那个位置,新增的数据将添加在集合末尾。

import java.util.*;
public class IteratorTest{
public static void main(String args[]){
Set set=new LinkedHashSet();
set.add("one");
set.add(23);
set.add(true);
set.add("two");
Iterator it=set.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
it.remove();
		}
	}
}

结果为

one 23 true two 

3)TreeSet

TreeSet可以对集合中的对象进行排序。成员一般为同一种类型。有两种排序方法,分别是自然排序和自定义排序

a、自然排序

import java.util.*;
public class IteratorTest{
public static void main(String args[]){
Set set=new TreeSet();
for(int i=1;i<=10;i++){
set.add(i);
}
Iterator it=set.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
it.remove();
		}
	}

结果为

1 2 3 4 5 6 7 8 9 10 

b、自定义排序

问题:按照学生姓名name进行降序排序 先定义student类

import java.util.*;
class student{
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	@Override
	public String toString() {
		return "student [name=" + name + ", age=" + age + "]";
	}
	
}

定义一个类MyComparator并实现Comparator接口 compareTo方法的使用:对于a.compareTo(b),如果a和b相等,则返回0。如果a大于b,则返回大于0的数。如果a小于b,则返回小于0的数。

static class MyComparator implements Comparator<Student>{
		@Override
		public int compare(Student s1, Student s2) {
			return s1.getName().compareTo(s2.getName()) * -1;
		}
	}

进行测试

	public static void main(String[] args) {
		Set<Student> set =new TreeSet<Student>(new MyComparator());
		Student s1 = new Student("Tom", 24);
		Student s2 = new Student("Marry", 20);
		Student s3 = new Student("Jerry", 23);
		set.add(s1);
		set.add(s2);
		set.add(s3);
		Iterator<Student> iterator = set.iterator();
		while(iterator.hasNext()){
			Student next = iterator.next();
			System.out.println(next.getName()+","+next.getAge());

		}

结果为:

Tom,24
Marry,20
Jerry,23

(4)List接口

List继承至Collection接口,实现类有ArraysList类和LinkedList类,他的特点是可以保存重复的元素,可以通过索引来访问元素。

List接口的常用方法

1、void add(int index,Object o):将对象o插入到索引index处 2、addAll(int index ,Collection c):将c集合添加到index索引处,从index处开始存储 3、Object get(int index):获得索引处的对象 4、Object set(int index,Object o):将index位置上的对象替换为对象o 5、Object remove(int index):删除index位置上的对象

1)ArraysList

ArrayList底层是数组。对元素的随机访问速度较快。

2)LinkedList

LinkedLis底层是链表。对元素的删除和插入的速度较快。


import java.util.*;

public class Test {
	
public static void main(String args[]){
	List list1=new ArrayList();
	List list2=new LinkedList();
	list1.add("Monday");
	list1.add("Tuesday");
	list1.add("Wednesday");
	list1.add("Thursday");
	list1.add("Friday");
	System.out.println("list1中的元素:"+list1);
	System.out.println("list1中索引值为1的元素:"+list1.get(1));
	
	//在索引为0的位置插入一个元素“weekend”
	list1.add(0, "weekend");
	System.out.println("在索引为0的位置添加一个元素weekend"+list1);
	
	//删除索引为0位置上的元素
	list1.remove(0);
	System.out.println("删除索引为0位置上的元素"+list1);
	
	//将索引为1的位置设置为"星期一"
	list1.set(1, "星期一");
	System.out.println("将索引为1的位置设置为\"星期一\""+list1);
	
	
	list2.addAll(list1);
	//获得索引为2的位置上的元素
	Object object = list2.get(2);
	System.out.println("删除索引为2位置上的元素"+object);
}
}

(5)Map接口

Map映射集合保存的是键值对对象,类似字典,当查找元素时,只要知道就能查到,他有三个实现类分别是HashMapTreeMapLinkedHashMap

Map接口中常用的方法

1、Object put(Object key,Object value)将键值对key-value添加到map 2、Object remove(Object key)将map中以key为键的键值对删除 3、Object putAll(Map mapping):将mapping添加到当前Map 4、void clear():清空当前Map 5、boolean containsKey(Object key):判断是否存在key键 6、boolean containsValue(Object value):判断是否存在value值 7、int size():返回键值对个数 8、boolean isEmpty():判断当前Map是否为空


import java.util.HashMap;
import java.util.Map;

public class MapTest {
	public static void main(String args[]){
		Map m1=new HashMap();
		Map m2=new HashMap();
		//将键值对key-value添加到map
		m1.put("one", "Monday");
		m1.put("two", "Tuesday");
		m1.put("three", "Wednesday");
		m1.put("four", "Thursday");
		m1.put("five", "Friday");
		System.out.println(m1);
		//将m1中以"one"为键的键值对删除
		m1.remove("one");
		System.out.println("将map中以key为键的键值对删除"+m1);
//		将m1添加到当前m2
		m2.putAll(m1);
		System.out.println("将m1添加到当前m2"+m2);
//		清空m1
		m1.clear();
		System.out.println("清空m1"+m1);
//		判断是否存在"two"键
		System.out.println("判断是否存在key键"+m2.containsKey("two"));
//		判断是否存在value值
		System.out.println("判断是否存在key键"+m2.containsValue("Friday"));
//		返回键值对个数
		System.out.println("返回键值对个数"+m2.size());
//		判断当前Map是否为空
		System.out.println("判断当前Map是否为空"+m2.isEmpty());
	}
}

结果为:

{four=Thursday, one=Monday, two=Tuesday, three=Wednesday, five=Friday}
将map中以key为键的键值对删除{four=Thursday, two=Tuesday, three=Wednesday, five=Friday}
将m1添加到当前m2{two=Tuesday, three=Wednesday, five=Friday, four=Thursday}
清空m1{}
判断是否存在key键true
判断是否存在key键true
返回键值对个数4
判断当前Map是否为空false

介绍两个常用的Map

1)HashMap

HashMap实现了Map接口,中文叫散列表。元素的排列顺序不固定,在遍历HashMap时,得到的映射关系是无序的。

import java.util.HashMap;
import java.util.Map;

public class MapTest {
	public static void main(String args[]){
		Map m1=new HashMap();
		//将键值对key-value添加到map
		m1.put("one", "Monday");
		m1.put("two", "Tuesday");
		m1.put("three", "Wednesday");
		m1.put("four", "Thursday");
		m1.put("five", "Friday");
		System.out.println(m1);
	}
}

结果为:

{four=Thursday, one=Monday, two=Tuesday, three=Wednesday, five=Friday}

可以看到,HashMap的存入顺序和输出顺序无关

2)LinkedHashMap

保留键的插入顺序,用equals方法检查键和值的相等性,成员可为任意的对象,若覆盖了equals方法,那么必须要修改hashCode方法

LinkedHashMap关注点结论
是否允许空Key和Value都允许空
是否允许重复数据Key重复会覆盖、Value允许重复
是否有序有序
是否线程安全非线程安全

LinkedHashMap保留键值对的存入顺序


import java.util.LinkedHashMap;
import java.util.Map;
public class MapTest {
	
	public static void main(String args[]){
		
		Map m1=new LinkedHashMap();
		m1.put("1", "星期一");
		m1.put("2", "星期三");
		m1.put("5", "星期五");
		m1.put("3", "星期二");
		m1.put("4", "星期四");
		System.out.println(m1);
	}
}
{1=星期一, 2=星期三, 3=星期二, 4=星期四, 5=星期五}

3)TreeMap

支持对键有序的遍历,实现了SortedMap接口,键成员要求实现Comparable接口,或者使用Comparator构造,TreeMap成员一般为同一类型。

import java.util.LinkedHashMap;
import java.util.Map;
import java.util.TreeMap;
public class MapTest {
	
	public static void main(String args[]){
		
		Map m1=new TreeMap();
		m1.put("1", "星期一");
		m1.put("2", "星期三");
		m1.put("5", "星期五");
		m1.put("3", "星期二");
		m1.put("4", "星期四");
		System.out.println(m1);
	}
}
{1=星期一, 2=星期三, 3=星期二, 4=星期四, 5=星期五}

tip:Integer、Double、String等已经实现了Comparable接口,所以上面的例子会实现自动排序哦~

在这里插入图片描述

创作不易,欢迎三连呀