Java基础-集合
集合入门
1、集合框架(体系概述)
集合类Collection:
-
为什么出现集合类?面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象进行操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
-
数组和集合类同是容器,有何不同?
数组虽然也可以存储对象,但长度是固定的;集合长度是可以变得,数组中可以存储基本数据类型,集合只能存储对象。
-
集合类的特点。
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
-
为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。
集合图:
Collection类属于java.util.*;包中
2、集合框架(共性方法)
import java.util.*;
class CollectionDemo
{
public static void main(String[]args)
{
method_1();
method_2();
}
public static void method_1()
{
//创建一个集合容器,使用Collection接口的子类ArrayList类
ArrayList al = new ArrayList();
//添加元素到容器al中。
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
//打印容器中的元素
System.out.println("al中有:"+al);
//获取个数,集合长度。
System.out.println("al.size :"+al.size());
//删除元素
al.remove(1);
System.out.println("删除java03是否成功?"+al.remove("java03"));
//清空集合
al.clear();
System.out.println("清空集合后al中有:"+al);
//判断元素
System.out.println("al中是否存在java03?"+al.contains("java03"));
System.out.println("al是否为空?"+al.isEmpty());
}
public static void method_2()
{
ArrayList al1 = new ArrayList();
ArrayList al2 = new ArrayList();
al2.add("java01");
al2.add("java02");
al2.add("java03");
al2.add("java04");
al1.add("java01");
al1.add("java02");
al1.add("java05");
al1.add("java06");
//取交集
al1.retainAll(al2);
System.out.println("al1取了al2的交集后的结果是"+al1);
//去掉相同的子集
al2.removeAll(al1);
System.out.println("al2被去掉了al1中相同的子集后的结果是:"+al2);
}
}
输出结果:
al中有:[java01, java02, java03, java04]
al.size :4
删除java03是否成功?true
清空集合后al中有:[]
al中是否存在java03?false
al是否为空?true
al1取了al2的交集后的结果是[java01, java02]
al2被去掉了al1中相同的子集后的结果是:[java03, java04]
图:
3、集合框架(迭代器)
-
什么是迭代器?
其实就是集合取出元素方式。就把取出方式定义在集合内部,这样取出方式就可以直接访问集合内容的元素,那么取出方式就被定义成内部类,而每一个容器的数据结构不同,所以取出的动作细节不一样,但是都有共性内容:判断和取出,那么可以将共性抽取,那么这些内部类都符合一个规则,该规则就是Iterator。
-
如何获取集合的取出对象呢?
通过一个对外提供的方式:iterator();
import java.util.*;
class CollectionDemo
{
public static void main(String[]args)
{
method_get();
}
public static void method_get()
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
Iterator it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
//另一种使用迭代器的方法,可以更省资源
System.out.println();
for(Iterator it1 = al.iterator();it1.hasNext();)//当for循环完毕,Iterator it1 = al.iterator()语句释放
{
System.out.println(it1.next());
}
}
}
输出结果:
java01
java02
java03
java04
java01
java02
java03
java04
4、集合框架(List集合共性方法)
Collection
|--List:元素是有序的,同时元素可以重复,因为该集合体系有索引
|--Set:元素是无序的,不能重复。
List(接口):特有方法:凡是可以操作角标的方法都是该体系特有方法。
-
增:
void add(int index,E element);//将指定的元素插入此列表中的指定位置。 boolean addAll(int index,Collection c);// 从指定的位置开始,将指定 collection 中的所有元素插入到此列表中。
-
删
E remove(int index);// 移除此列表中指定位置上的元素。
-
改
E set(int index, E element);//用指定的元素替代此列表中指定位置上的元素。
-
查
E get(int index);//返回此列表中指定位置上的元素。 List<E> subList(int fromIndex , int toIndex);//返回列表中指定的 fromIndex(包括 )和 toIndex(不包括)之间的部分视图。 ListIterator<E> listIterator();//返回此列表元素的列表迭代器(按适当顺序)。
演示代码:
import java.util.*;
class ListDemo
{
public static void main(String[]args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
System.out.println("原集合al:"+al);
//在指定的位置添加元素:
al.add(1,"java09");
System.out.println("al.add(1,\"java09\"):"+al);
//删除指定位置元素
al.remove(2);
System.out.println("al.remove(2):"+al);
//修改元素
al.set(1,"java0001");
System.out.println("al.set(1,\"java0001\"):"+al);
//通过角标获取元素
System.out.println("al.get(1):"+al.get(1));
//获取所有元素
//方式1
for(int x = 0;x<al.size();x++)
{
System.out.println(al.get(x));
}
//方式2
System.out.println();
Iterator it = al.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}
输出结果:
原集合al:[java01, java02, java03, java04]
al.add(1,"java09"):[java01, java09, java02, java03, java04]
al.remove(2):[java01, java09, java03, java04]
al.set(1,"java0001"):[java01, java0001, java03, java04]
al.get(1):java0001
java01
java0001
java03
java04
java01
java0001
java03
java04
5、集合框架(ListIterator)
演示代码:
import java.util.*;
class ListDemo
{
public static void main(String[]args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
System.out.println("原集合al:"+al);
//通过indexOf获取对象的位置
System.out.println("java02的index是:"+al.indexOf("java02"));
//获取子对象集
List sub = al.subList(1,3);
System.out.println("下标1到2的子对象集是:"+sub);
}
}
输出结果:
原集合al:[java01, java02, java03, java04]
java02的index是:1
下标1到2的子对象集是:[java02, java03]
演示代码:下面这段代码会引起异常,原因是并发操作。
import java.util.*;
class ListDemo
{
public static void main(String[]args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
System.out.println("原集合al:"+al);
Iterator it = al.iterator();
//下面代码目的是在迭代过程中,使用集合的方法来对it对象中的元素进行添加或删除元素。
while(it.hasNext())
{
Object obj = it.next();
if(obj.equals("java02"))
{
al.add("java09");//这是集合的方法,会引起并发异常
}
System.out.println("obj"+obj);
}
}
}
输出结果:
原集合al:[java01, java02, java03, java04]
objjava01
objjava02
Exception in thread "main" java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:886)
at java.util.ArrayList$Itr.next(ArrayList.java:836)
at day09.ListDemo.main(Outer.java:18)
-
以上代码引发了问题,就是如何在迭代器中进行元素的添加或删除呢?
List集合特有的迭代器,ListIterator是Iterator的子接口。在使用Iterator中的迭代器迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常。所以,在迭代,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断、取出和删除的操作。如果想要其他的操作如:添加、修改等,就需要使用其子接口:ListIterator,该接口只能通过ListIterator方法获取
改进代码如下:
import java.util.*;
class ListDemo
{
public static void main(String[]args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add("java04");
System.out.println("原集合al:"+al);
ListIterator li = al.listIterator();
while(li.hasNext())
{
Object obj = li.next();
//添加
if(obj.equals("java02"))
{
li.add("java09");
}
//修改
if(obj.equals("java03"))
{
li.set("java003");
}
}
System.out.println("修改后al:"+al);
}
}
输出结果:
原集合al:[java01, java02, java03, java04]
修改后al:[java01, java02, java09, java003, java04]
6、集合框架(List集合具体对象的特点)
List
|--ArrayList:底层的数据结构使用的是数组结构,特点:查询快,但增删稍慢,线程不同步。
|--LinkedList:底层使用链表数据结构,增删速度快,查询慢。
|--Vector:底层是数组数据结构,被ArrayList替代了,但它们间不同的是Vector线程同步。
7、集合框架(Vector中的枚举)
import java.util.*;
class VectorDemo
{
public static void main(String[]args)
{
Vector v = new Vector();
v.add("java01");
v.add("java02");
v.add("java03");
v.add("java04");
Enumeration en = v.elements();
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
}
}
输出结果:
java01
java02
java03
java04
-
枚举就是Vector特有的取出方式。
发现枚举和迭代器很像,其实枚举和迭代是一样的,因为枚举的名称以及方法的名称都过长,所以被迭代器取代了,枚举就很少被人使用了。
8、集合框架(LinkedList)
LinkedList特有方法:
void addFirst(E e);//将指定元素插入此列表的开头。
void addLast(E e);// 将指定元素添加到此列表的结尾。
boolean offerFirst(E e );//在此列表的开头插入指定的元素。JDK1.6版本
boolean offerLast(E e);//在此列表末尾插入指定的元素。JDK1.6版本
E getFirst();//返回此列表的第一个元素。
E getLast();// 返回此列表的最后一个元素。
E peekFirst();//获取但不移除此列表的第一个元素;如果此列表为空,则返回 null。JDK1.6版本
E peekLast();//获取但不移除此列表的最后一个元素;如果此列表为空,则返回 null。JDK1.6版本
E removeFirst();//移除并返回此列表的第一个元素。
E removeLast();//移除并返回此列表的最后一个元素。
E pollFirst();//获取并移除此列表的第一个元素;如果此列表为空,则返回 null。JDK1.6版本
E pollLast();//获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。JDK1.6版本
因为如果集合中没有元素,会出现NoSuchElementException,在JDK1.6出现了替代方法,以上JDK1.6版本的功能,这些方法不会返回异常而是null。
9、集合框架(LinkedList练习)
使用LinkedList模拟一个堆栈或者队列数据结构。 堆栈:先进后出,如同一个杯子。 队列:先进先出,如同一个水管。 测试代码:
import java.util.*;
class DuiLie
{
private LinkedList link;
DuiLie()
{
link = new LinkedList();
}
public void bianli()
{
for(int x = 0;x<link.size();x++)
{
System.out.print(link.get(x)+" ");
}
System.out.println();
}
public void myAdd(Object obj)
{
link.addFirst(obj);
}
public Object myGet()
{
return link.removeLast();
}
public boolean isNull()
{
return link.isEmpty();
}
}
class LinkedListTest
{
public static void main(String []args)
{
DuiLie dl = new DuiLie();
dl.myAdd("java01");
dl.myAdd("java02");
dl.myAdd("java03");
dl.myAdd("java04");
dl.bianli();//遍历
while(!dl.isNull())
{
System.out.println(dl.myGet());
}
}
}
输出结果:
java04 java03 java02 java01
java01
java02
java03
java04
10、集合框架(ArrayList练习)
去除ArrayList集合中的重复元素
import java.util.*;
class ArrayListTest
{
public static ArrayList SingleElement(ArrayList al)
{
//定义一个临时容器
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!newAl.contains(obj))
{
newAl.add(obj);
}
}
return newAl;
}
public static void main(String[]args)
{
ArrayList al = new ArrayList();
al.add("java01");
al.add("java01");
al.add("java02");
al.add("java04");
al.add("java06");
al.add("java01");
System.out.println("原al:"+al);
System.out.println("新al:"+SingleElement(al));
}
}
输出结果:
原al:[java01, java01, java02, java04, java06, java01]
新al:[java01, java02, java04, java06]
11、集合框架(ArrayList练习)
将自定义对象作为元素存储到ArrayList集合中,并去除重复元素。 比如:存人对象:同姓名同年龄,视为同一个人,为重复元素。 思路: 1、对人描述 2、定义容器,将人存入。 3、取出。
代码:
import java.util.*;
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name ;
}
public int getAge()
{
return age;
}
public boolean equals(Object obj)//List集合判断元素是否相同,依据是元素(对象)的equals方法
{
if(!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
}
class ArrayListTest2
{
public static ArrayList SingleElement(ArrayList al)
{
//定义一个容器
ArrayList newAl = new ArrayList();
Iterator it = al.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(!(newAl.contains(obj)))//即调用了Person类中的自定义equals函数
{
newAl.add(obj);
}
}
return newAl;
}
public static void main(String []args)
{
ArrayList al = new ArrayList();
al.add(new Person("lisi01",30));
al.add(new Person("lisi02",33));
al.add(new Person("lisi03",22));
al.add(new Person("lisi04",30));
al.add(new Person("lisi01",30));
al = SingleElement(al);
Iterator it = al.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
输出结果:
lisi01::30
lisi02::33
lisi03::22
lisi04::30
12、集合框架(HashSet)
Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。 Set
|---HashSet:底层数据结构是哈希表
|---TreeSet
Set集合的功能和Collection是一致的。
测试代码:
import java.util.*;
class HashSetDemo
{
public static void main(String []args)
{
HashSet hs = new HashSet();
hs.add("java01");
hs.add("java02");
hs.add("java03");
hs.add("java04");
Iterator it = hs.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}//无序存,按哈希表顺序存。
}
}
输出结果:
java04
java03
java02
java01
13、集合框架(HashSet存储自定义对象)
往HashSet集合中存入自定义对象,姓名和年龄相同为同一个人,重复元素。
import java.util.*;
class HashSetTest
{
public static void main(String []args)
{
HashSet hs = new HashSet();
hs.add(new Person("al",11));
hs.add(new Person("a2",12));
hs.add(new Person("a3",13));
hs.add(new Person("a2",12));
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name ;
}
public int getAge()
{
return age;
}
public boolean equals(Object obj)//List集合判断元素是否相同,依据是元素(对象)的equals方法
{
System.out.println("equals() run");
if(!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public int hashCode()
{
System.out.println("hashCode() run");
//字符串类型的变量可以调用字符串自己的哈希值函数,返回字符串自己独有的哈希值
return this.name.hashCode()+this.age*37; //为了保证哈希值唯一而在对象内容不一样的情况下不用去调用equals方法
}
}
输出结果:
hashCode() run
hashCode() run
hashCode() run
hashCode() run
equals() run
al::11
a3::13
a2::12
HashSet是如何保证元素唯一性的呢?
是通过元素(对象)的两个方法:hashCode和equals来完成,如果元素的hashCode值相同,才会判断equals是否为true,如果元素的hashCode值不同,不会调用equals。
14、集合框架(HashSet判断和删除的依据)
import java.util.*;
class HashSetTest
{
public static void main(String []args)
{
HashSet hs = new HashSet();
Person p1 = new Person("a2",12);
hs.add(new Person("al",11));
hs.add(p1);
hs.add(new Person("a3",13));
System.out.println("....");
//hs.add(new Person("a2",12));
System.out.println("测试判断是否包含的功能:"+hs.contains(new Person("a2",12)));
hs.remove(p1);
/*
Iterator it = hs.iterator();
while(it.hasNext())
{
Person p = (Person)it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
*/
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name = name;
this.age = age;
}
public String getName()
{
return name ;
}
public int getAge()
{
return age;
}
public boolean equals(Object obj)//List集合判断元素是否相同,依据是元素(对象)的equals方法
{
System.out.println("equals() run");
if(!(obj instanceof Person))
{
return false;
}
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
public int hashCode()
{
System.out.println("hashCode() run");
//字符串类型的变量可以调用字符串自己的哈希值函数,返回字符串自己独有的哈希值
return this.name.hashCode()+this.age*37; //为了保证哈希值唯一而在对象内容不一样的情况下不用去调用equals方法
}
}
输出结果:
hashCode() run
hashCode() run
hashCode() run
....
hashCode() run
equals() run
测试判断是否包含的功能:true
hashCode() run
对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。