详解Java集合
1、什么是集合
集合是存放一组数据的容器,同时能够对数据进行存储,查询,操作等。
我们也听说过“数组”,同样的,“数组”也可以进行数据的存储,查询和操作。
集合与数组两者的区别就是
(1)数组长度不可改变,而集合的长度可以
随需求变动
(2)数组中可以存放基本类型数据和对象,
而集合只能存储对象
2、类图
只画出主要的类图,因为画太多就显得太乱了。
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]
7)boolean 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个实现类分别是HashSet
、LinkedHashSet
、TreeSet
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映射集合保存的是键值对
对象,类似字典,当查找元素时,只要知道键
就能查到值
,他有三个实现类分别是HashMap
,TreeMap
,LinkedHashMap
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接口,所以上面的例子会实现自动排序哦~