1.集合的概念
面向对象对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象
最常用的一种容器。
2.集合的特点
(1)集合是用来存储对象的,而且存储的是对象的地址而不是对象本身。
(2)集合中可以存储任何类型的对象,并且集合的长度可变。
3.集合和数组的区别
(1)集合:只可以存储对象,长度可变,可以存储不同类型的对象。
(2)数组:既可以存储对象又可以存储基本数据类型,长度固定,数组只能存储类型相同的元素。
二、集合的构成及分类
Collection(接口)
|----------List(子接口):元素是有序的,可以重复。因为该集合体系有索引
|-----ArrayList:底层使用的是数组结构。特点:查询速度很快,增删速度稍慢,线程不同步。
|-----LinkedList:底层使用的是链表结构。特点:增删速度快,查询稍慢。
|-----Vector:底层使用的是数组结构。特点:查询、增删速度稍慢,线程同步,被ArrayList替代。
|----------Set(子接口):元素是无序的(存入和取出的顺序不一定一致),不可以重复。
|-----HashSet:底层使用的是哈希表结构,线程不同步。
|-----TreeSet:底层使用的是二叉树结构,可以对Set集合中的元素进行排序。
为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都不同。这个存储方式称为数据结构。
三、Collection的共性方法
1.添加元素:boolean add(Object obj)
2.删除元素:boolean remove(元素)
3.清空集合:void clear()
4.判断元素是否存在该集合中:boolean contains(元素)
判断集合是否为空:boolean isEmpty()
5.获取元素个数:int size()
6.取出元素利用迭代器:Interator it=集合.iterator();
示例:
package com.itheima;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Test038
{
/**
* @param args
*/
public static void main(String[] args)
{
//定义一个ArrayList集合对象
Collection collection = new ArrayList();
//添加元素
collection.add("itheima-01");
collection.add("itheima-02");
collection.add("itheima-03");
collection.add("itheima-04");
//打印集合及集合的长度
System.out.println(collection);
System.out.println(collection.size());
//移除元素
collection.remove("itheima-03");
// al.clear(); //清空集合
System.out.println(collection);
//判断元素是否存在
System.out.println(collection.contains("itheima-03"));
//获取两个集合的交集
Collection collection2 = new ArrayList();
collection2.add("itheima-01");
collection2.add("itheima-05");
collection2.add("itheima-03");
collection2.add("itheima-04");
collection.retainAll(collection2);
System.out.println(collection);
//去除与另一个集合的共同元素
collection.removeAll(collection2);
System.out.println(collection);
//获取迭代器,用于取出集合中的元素
Iterator it = collection2.iterator();
while(it.hasNext())
{
Object obj = it.next();
System.out.println(obj);
if(obj.equals("itheima-04"))
it.remove(); //移除元素
// collection2.remove(obj);//在迭代过程中,不可以用集合的方法操作元素,只可以 //用迭代器中的方法
}
System.out.println(collection2);
}
}
四、List集合
1.List集合的特有方法
凡是可以操作脚标的方法都是该体系特有的方法。
在指定位置添加元素:void add(int index,元素)
删除指定位置的元素:元素类型 remove(int index)
修改指定位置的元素:元素类型 set(int index,newElement)
通过角标获取指定位置元素:元素类型 get(int index)
注意:List集合判断元素是否相同,依据的是元素的equals()方法,contains方法和remove方法会调用元素equals方法。
2.List集合的特有迭代器:ListIterator
ListIterator 是Iterator的子接口。
在迭代的过程中,不可以通过集合对象的方法来操作。集合中的元素,会发生ConcurrentModificationException异常。所以在迭代时,只能用迭代器的方法来操作元素,可是Iterator的方法是有限的,只能对元素进行判断,取出,删除的动作。如果想要其他的操作,如添加、修改等,就需要使用其子接口ListIterator。
创建ListIterator对象:ListIterator li=al.listIterator();
示例:
package com.itheima;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class Test039
{
/**
* @param args
*/
public static void main(String[] args)
{
//定义一个ArrayList集合对象
List list = new ArrayList();
//添加元素
list.add("itheima-01");
list.add("itheima-02");
list.add("itheima-03");
list.add("itheima-04");
//在指定位置插入元素
list.add(4, "itheima-05");
System.out.println(list);
//删除指定位置的元素
list.remove(3);
System.out.println(list);
//修改指定位置的元素
list.set(2, "java02");
System.out.println(list);
//获取指定位置元素
System.out.println(list.get(2));
//获取元素位置
System.out.println(list.indexOf("itheima-04"));
//获取集合中的所有元素
for (int i = 0; i < list.size(); i++)
{
System.out.println(list.get(i));
}
Iterator it = list.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
//List集合特有的迭代器ListIterator
ListIterator li = list.listIterator();
while(li.hasNext())
{
Object obj = li.next();
if(obj.equals("itheima-02"))
li.add("itheima--6"); //添加元素
}
System.out.println(list);
//从后向前迭代
while(li.hasPrevious())
{
System.out.println(li.previous());
}
}
}
3.LinkedList
(1)它的特有方法
添加元素:
void addFirst(E e)//在集合的第一个位置添加元素
void addLast(E e) //在集合的最后一个位置添加元素
获取元素:
E getFirst() //获取此集合的第一个元素
E getLast() //获取此集合的最后一个元素
删除元素:
E removeFirst()//移除此集合的第一个元素,并返回此元素
E removeLast() //移除此集合的最后一个元素,并返回此元素
(2)对于此集合而得到的思想
由于此集合具有在第一个位置和最后一个位置添加元素的特性以及移除第一个位置和移除第二个位置元素的额特性。则可以通过此集合来模拟一个堆栈或者队列的数据结构
具体程序如下:
具体程序如下:
/**
需求:使用LinkedList模拟一个堆栈或者队列的数据结构。
思路:1.要想模拟堆栈或者队列的数据结构 首先应该知道他们的特点
堆栈:先进后出
队列:先进先出
2.根据他们的特点 然后再创建相应的方法--存入方法 和取出方法
3.使用LinkedList中的方法来实现堆栈和队列
步骤:
1,定义一个类来实现堆栈或者队列
2,定义此类中的成员变量和成员函数
3,成员函数即实现此堆栈或者队列的特点 即利用LinkedList中的特有方法来实现
*/
import java.util.*;
class DuiZhan
{
private LinkedList ll;
DuiZhan()
{
ll=new LinkedList();
}
//实现存放的功能
public void set(Object obj)
{
ll.addFirst(obj);
}
//实现获取的功能
public Object get()
{
return ll.removeFirst();
}
public int size()
{
return ll.size();
}
public boolean isNull()
{
return ll.isEmpty();
}
}
class LinkedListDemo
{
public static void main(String[] args)
{
DuiZhan dz=new DuiZhan();
dz.set("java05");
dz.set("java02");
dz.set(3);
int y=dz.size();
for (int x=0; x<y;x++ )//此处不能直接写x<dz.size() 因为循环一次则调用一次dz.size()
//所以长度会慢慢减小
{
sop(dz.get());
}
}
public static void sop(Object b)
{
System.out.println(b);
}
}
五、Set集合
Set集合中的方法和Collection的共性方法是一样的。下面具体介绍Set的两个子类的作用和方法
1.HashSet
(1)存储的元素是无序的,元素是不可以重复。
(2)HashSet是如何保证元素的唯一性的呢?
是通过元素的两个方法:hashCode和equals来完成的。如果元素的hashCode值相同,才会判断equals是否是true。如果元素的hashCode值不同,不会调用equals方法。所以对于自定义对象,要存入HashSet集合中,为了保证元素的唯一性,必须复写HashCode方法和equals方法。
(3)对于HashSet集合中判断元素是否存在以及删除元素,依赖的也是HashCode方法和equals方法
(4)注意:hashCode方法本身比较的是对象的地址值。所以若不复写,则是去除不了重复元素的。
示例:
例子:需求:向HashSet集合中存入自定义Person对象
import java.util.*;
class HashSetTest
{
public static void sop(Object b)
{
System.out.println(b);
}
public static void main(String[] args)
{
HashSet hs=new HashSet();
hs.add(new Person("a1",71));
hs.add(new Person("a2",73));
hs.add(new Person("a3",74));
hs.add(new Person("a1",71));
//遍历此集合
Iterator it=hs.iterator();
while (it.hasNext())
{
//向下转型,为了用Person类的特有方法
Person p=(Person)it.next();
sop(p.getName()+"::"+p.getAge());
}
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
//复写hashCode方法
public int hashCode()
{
return name.hashCode()+age;
}
//复写equals方法
public boolean equals(Object obj)
{
if (!(obj instanceof Person))
{
return false;
}
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
2.TreeSet
(1)TreeSet集合的底层数据结构为二叉树
(2)此集合可以对Set集合中的元素进行排序(按字母的自然顺序,且大写的在小写的字母前面)
(3)TreeSet集合对元素进行排序的原理
此元素需要实现Comparable接口并复写comparaTo方法,才能对元素进行排序
(4)TreeSet集合存储自定义对象,对对象实现排序功能的方法有两种;
第一,元素自身具备比较性,即实现Comparable接口并复写comparaTo方法
第二,集合本身具备比较性,即在集合的构造函数里传入Comparator接口类型的对象。即,定义一个类实现Comparator接口,并覆盖compara方法。并将此类对象作为参数传递给TreeSet集合的构造函数中。
注意:当这两中排序方式同时都存在时,则集合本身具备比较性优先。
注意:在比较的时候,当主要条件相同时,则判断次要条件。
示例:
/*
需求:向集合TreeSet中存入自定义对象Student,并按年龄进行排序,将年龄和名字相同者视为同一个人。
*/
//元素自身具备比较性
class Student implements Comparable
{
private int age;
private String name;
Student(int age,String name)
{
this.age=age;
this.name=name;
}
//复写Comparable接口的方法Comparable
public int comparaTo(Object obj)
{
if (!(obj instanceof Student))
{
throw new RuntimeException("不是学生对象");
}
Student s=(Student)obj;
if (this.age>s.age)
return 1;
if (this.age=age)//当主要条件相等时,比较次要条件
return this.name.comparaTo(p.name);
return -1;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
}
//第二种方式排序,即用比较器,使集合自身具备比较性
class MyCompara implements Comparator
{
public int compara(Object 01,Object 02)
{
Student s1=(Student)01;
Student s2=(Student)02;
//以姓名排序
int num=s1.getName().comparaTo(s2.getName());
if (num==0)
{
//当主要条件相同时,看次要条件。
return new Integer(s1.getAge()).comparaTo(new Integer(s2.getAge()));
}
return num;
}
}
class TreeSetTest
{
public static void main(String[] args)
{
TreeSet ts=new TreeSet(new MyCompara());//让集合自身具备比较功能
ts.add(new Student("lisi02",22));
ts.add(new Student("lisi02",21));
ts.add(new Student("lisi007",20));
ts.add(new Student("lisi09",19));
ts.add(new Student("lisi06",18));
ts.add(new Student("lisi06",18));
Iterator it = ts.iterator();
//对集合进行遍历
while(it.hasNext())
{
Student stu = (Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
六、Map集合
1.Map集合并不是Collection的一种,它是独立的接口
2.Map集合的特点
该集合存储键值对,一对一对往里存,而且保证键的唯一性。
3.Map的子类:
(1)Hashtable:底层是哈希表数据结构,不可以存入null键和null值用作键的对象必须实现hashCode方法和equals 方法;该集合是线程同步的。
(2)HashMap:底层是哈希表数据结构,允许使用null值和null键,该集合是不同步的。效率较高
(3)TreeMap:底层是二叉树数据结构,线程不同步。可以用于给Map集合中的键进行排序。
Map和Set很像,其实Set底层就是使用了Map集合。
4.Map集合的共性方法
添加元素: V put(K key, V value )
删除元素: V remove(Object key)
清空集合:void clear()
判断: boolean containsKey(Object key)
如果此映射包含指定键的映射关系,则返回 true。
boolean containsValue(Object value)
如果此映射将一个或多个键映射到指定值,则返回 true
boolean isEmpty()//判断集合是否是空的。
获取: V get(Object key) //获取键所对应的值
int size() //获取集合的大小
5、对于Map集合中元素的取出方式
(1)利用keySet:将map中的所有键存入set集合,因为set具备迭代器,所以可以通过迭代器方式取出所有的键,再根据get方法,获取每一个键对应的值。
(2)entrySet:将map集合的映射关系直接存入到了set集合中,而这个关系数据类型就是Map.Entry,Entry其实就是Map中的一个static内部接口。
6.Map集合保证元素唯一性
HashMap保证元素唯一性的原理和HashSet是一样的,所以不再赘述
TreeSet对元素的排序原理和TreeSet是一样的,同样不再赘述。
代码:
import java.util.*;
class MapDemo2
{
public static void main(String[] args)
{
Map<String,String> map = new HashMap<String,String>();
map.put("02","zhangsan2");
map.put("03","zhangsan3");
map.put("01","zhangsan1");
map.put("04","zhangsan4");
//第二种排序方式
//将Map集合中的映射关系取出。存入到Set集合中。
Set<Map.Entry<String,String>> entrySet = map.entrySet();
Iterator<Map.Entry<String,String>> it = entrySet.iterator();
while(it.hasNext())
{
Map.Entry<String,String> me = it.next();
String key = me.getKey();
String value = me.getValue();
System.out.println(key+":"+value);
}
/*第一种排序方式
//先获取map集合的所有键的Set集合,keySet();
Set<String> keySet = map.keySet();
//有了Set集合。就可以获取其迭代器。
Iterator<String> it = keySet.iterator();
while(it.hasNext())
{
String key = it.next();
//有了键可以通过map集合的get方法获取其对应的值。
String value = map.get(key);
System.out.println("key:"+key+",value:"+value);
}
*/
}
}
七、练习
1.对于HashMap集合的练习
<span style="font-family:SimSun;">/*
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
获取map集合中的元素。
*/
import java.util.*;
class Student
{
private String name;
private int age;
Student(String name,int age)
{
this.name = name;
this.age = age;
}
//复写hashCode方法
public int hashCode()
{
return name.hashCode()+age*34;
}
//复写equals方法
public boolean equals(Object obj)
{
if(!(obj instanceof Student))
throw new ClassCastException("类型不匹配");
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
public String toString()
{
return name+":"+age;
}
}
class MapTest
{
public static void main(String[] args)
{
HashMap<Student,String> hm = new HashMap<Student,String>();
hm.put(new Student("lisi1",21),"beijing");
hm.put(new Student("lisi1",21),"tianjin");
hm.put(new Student("lisi2",22),"shanghai");
hm.put(new Student("lisi3",23),"nanjing");
hm.put(new Student("lisi4",24),"wuhan");
//利用 keySet取出元素
Set<Student> keySet = hm.keySet();
Iterator<Student> it = keySet.iterator();
while(it.hasNext())
{
Student stu = it.next();
String addr = hm.get(stu);
System.out.println(stu+".."+addr);
}
}
}</span>
2.对TreeSet集合的练习
/*
练习:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。
希望打印结果:a(1)c(2).....
通过结果发现,每一个字母都有对应的次数。
说明字母和次数之间都有映射关系。所以选择map
思路:
1,将字符串转换成字符数组。因为要对每一个字母进行操作。
2,定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合。
3,遍历字符数组。
将每一个字母作为键去查map集合。
如果返回null,将该字母和1存入到map集合中。
如果返回不是null,说明该字母在map集合已经存在并有对应次数。
那么就获取该次数并进行自增。,然后将该字母和自增后的次数存入到map集合中。覆盖调用原理键所对应的值。
4,将map集合中的数据变成指定的字符串形式返回。
*/
import java.util.*;
class MapTest3
{
public static void main(String[] args)
{
String s= charCount("ak+abAf1c,dCkaAbc-defa");
System.out.println(s);
}
public static String charCount(String str)
{
char[] chs = str.toCharArray();
//将字母和字母出现的次数作为映射存入集合中
TreeMap<Character,Integer> tm = new TreeMap<Character,Integer>();
int count = 0;
//遍历数组
for(int x=0; x<chs.length; x++)
{
if(!(chs[x]>='a' && chs[x]<='z' || chs[x]>='A' && chs[x]<='Z'))
continue;
//去集合中找看是否有此映射关系
Integer value = tm.get(chs[x]);
if(value!=null)
count = value;
count++;
tm.put(chs[x],count);//直接往集合中存储字符和数字,为什么可以,因为自动装箱。
count = 0;
StringBuilder sb = new StringBuilder();
//取出集合中的元素,并存入StringBuilder中
Set<Map.Entry<Character,Integer>> entrySet = tm.entrySet();
Iterator<Map.Entry<Character,Integer>> it = entrySet.iterator();
while(it.hasNext())
{
Map.Entry<Character,Integer> me = it.next();
Character ch = me.getKey();
Integer value = me.getValue();
sb.append(ch+"("+value+")");
}
return sb.toString();
}
}