------- android培训、java培训、期待与您交流! ----------
一.概述
1.为什么会出现集合类?
面向对象的语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的方式。
2.集合类特点:
集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
3.和数组的区别:
数组和集合都是容器,只不过它们存储的方式不一样。
数组可以存储对象,也可以存储基本数据类型,而且数组的长度是固定的。
集合只能用于存储对象,对象可以是不同类型的,集合的长度是可变的。
4.集合类的关系:
二 .Collection接口
1.共性方法:
添加: add(e);
删除: remove(e); removeAll(collection);
判断:contains(e); isEmpty();
获取:iterator(); size();
获取交集:retainAll();
集合变为数组:toArray();
2.Collection接口有两个子接口:
List(列表),Set(集)
List:可存放重复元素,元素存取是有序的。因为该集合体系有索引。
Set:不可以存放重复元素,元素存取是无序的。
三.迭代
1.迭代是取出集合中元素的一种方式。会直接访问集合中的元素。
2.迭代器通过内部类的形式进行描述。这些内部类都符合一个规则:Iterator;
因为Collection中有iterator方法,所以每一个子类集合对象都具备迭代器。
3.通过容器的iterator()方法获取内部类对象。
4.用法:
// 方式一:
for(Iterator iter = a.iterator();iter.hasNext(); )
{
System.out.println(iter.next());
}
// 方式二:
Iterator iter = l.iterator();
while(iter.hasNext())
{
System.out.println(iter.next());
}
5.迭代器的方法:
next() // 返回迭代的下一个元素。
boolean hasNext() // 如果仍有元素可以迭代,则返回 true。
注意:
迭代器在Collcection接口中是通用的,它替代了Vector类中的Enumeration(枚举)。
迭代器的next方法返回值类型是Object,所以要记得类型转换。
四.List
1.List接口中常用的类:
Vector:底层是数组数据结构。线程同步。被ArrayList替代了。因为效率低。
ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快。但是增删稍慢。线程不同步。
LinkedList:底层使用的链表数据结构。特点:增删速度很快,查询稍慢。线程不同步。
2.取出LIst集合中元素的方式:
get(int index):通过脚标获取元素。
iterator():通过迭代方法获取迭代器对象
List集合用元素的equals()方法判断元素是否相同。
3. 特有方法:凡是用于操作角标的方法都是该体系特有方法
增:void add(int index, E element)//在列表的指定位置插入指定元素。
boolean addAll(int index, Collection<? extends E> c) //将指定 collection中的所//有元素都插入到列表中的指定位置。
删: remove(int index) // 移除列表中指定位置的元素。
改:set(int index, E element) //用指定元素替换列表中指定位置的元素。
查: subList(int fromIndex, int toIndex) // 返回列表中指定的 fromIndex(包括和 toIndex(不包括)之间的部分视图。
listIterator() // 返回此列表元素的列表迭代器。
int indexOf(Object o) //获取制定元素的位置。
get(int index) //返回列表中指定位置的元素。
注意:contains()方法和remove()方法底层都依赖于元素的equals()方法。
4.List集合特有的迭代器:
ListIterator: ListIterator是Iterator的子接口。
该接口可以对元素进行添加,修改,该接口只能通过List集合的listItertor方法获取。
注意:在迭代时,不可以通过集合对象的方法操作集合中的元素,ConcurrentModificationException异常。
在迭代时,只能用迭代器的方法操作元素,Iterator方法有限,只能对元素判断,取出,删除操作。
代码:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
//ArrayList示例
class ListDemo {
public static void main(String[] args) {
method_1();
}
public static void method()
{
ArrayList a1=new ArrayList();
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");
sop("原集合是:"+a1);
//在指定位置添加元素。
a1.add(1,"java09");
//删除指定位置的元素。
//al.remove(2);
//修改元素。
//al.set(2,"java007");
//通过角标获取元素。
sop("get(1):"+a1.get(1));
sop(a1);
//获取所有元素。
for(int x=0; x<a1.size(); x++)
{
System.out.println("a1("+x+")="+a1.get(x));
}
Iterator it = a1.iterator();
while(it.hasNext())
{
sop("next:"+it.next());
}
}
public static void method_1()
{
ArrayList a1=new ArrayList();
a1.add("java01");
a1.add("java02");
a1.add("java03");
a1.add("java04");
//在迭代过程中,准备添加或者删除元素。
Iterator it = a1.iterator();
while(it.hasNext())
{
Object obj = it.next();
if(obj.equals("java02"))
//al.add("java008");
it.remove();//将java02的引用从集合中删除了。
sop("obj="+obj);
}
sop(a1);
//列表迭代器
ListIterator li = a1.listIterator();
//sop("hasPrevious():"+li.hasPrevious()); false 迭代前有没有
while(li.hasNext())
{
Object obj = li.next();
if(obj.equals("java02"))
//li.add("java009");
li.set("java006");
}
while(li.hasPrevious())
{
sop("pre::"+li.previous()); //逆向打印
}
sop(a1);
}
public static void sop(Object obj)
{
System.out.println(obj);
}
}
五.枚举和Vector
1.枚举是Vector特有的取出方式,枚举和迭代器一样。因为枚举的名称和方法的名称定义都过长,所以枚举被迭代器取代。
代码:
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());
}
}
}
六.LinkedList
1.特有方法:
添加:
void addFirst(E e) //将指定元素插入此列表的开头。
void addLast(E e) //将指定元素添加到此列表的结尾。
获取:
获取元素,但不删除元素。如果集合中没有元素,会出现NoSuchElementException
getFirst() // 返回此列表的第一个元素。
getLast() //返回此列表的最后一个元素。
删除:获取元素,但是元素被删除。如果集合中没有元素,会出现NoSuchElementException
removeLast() //移除并返回此列表的最后一个元素。
removeLast() // 移除并返回此列表的最后一个元素。
2.jdk1.6之后出现的替代方法
添加:
offerFirst ();//在此列表的开头插入指定的元素。
offerLast ();//在此列表末尾插入指定的元素。
获取:获取元素,但不删除元素。如果集合中没有元素,会返回null。
peekFirst();//获取但不移除此列表的第一个元素;如果此列表为空,则返回 //null。
peekLast();//获取但不移除此列表的最后一个元素;如果此列表为空,则返回 //null。
删除: 获取元素,并删除元素。如果集合中没有元素,会返回null。
pollFirst();//获取并移除此列表的第一个元素;如果此列表为空,则返回 null。
pollLast();//获取并移除此列表的最后一个元素;如果此列表为空,则返回 null。
代码:
import java.util.*;
//LinkedList示例
class LinkedListDemo {
public static void main(String[] args) {
//创建集合对象
LinkedList link = new LinkedList();
//在集合中添加内容
link.addLast("java01");
link.addLast("java02");
link.addLast("java03");
link.addLast("java04");
while (!link.isEmpty()) {
sop(link.removeLast());
}
}
//自定义打印方法
public static void sop(Object obj) {
System.out.println(obj);
}
}
七.Set
|--Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复。、
|--HashSet:底层数据结构是哈希表。是线程不安全的。不同步。
HashSet是如何保证元素唯一性:
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才会判断equals是否为true。
如果元素的hashcode值不同,不会调用equals。
注意: 对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
|--TreeSet:可以对Set集合中的元素进行排序。默认按照字母的自然排序。底层数据结构是二叉树。
保证元素唯一性的依据:compareTo方法return 0。
Set集合的功能和Collection是一致的。
1.HashSet
对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
代码:
import java.util.HashSet;
import java.util.Iterator;
/*
* 往HashSet中存入自定义对象,
* 姓名年龄相同的为同一个人 重复元素
* */
public class HashSetTest {
//自定义打印方法
public static void sop(Object obj) {
System.out.println(obj);
}
public static void main(String[] args) {
//创建HashSet对象
HashSet hs = new HashSet();
//往HashSet中添加内容
hs.add(new Person("a1", 11));
hs.add(new Person("a2", 12));
hs.add(new Person("a3", 13));
//迭代器
Iterator it = hs.iterator();
while (it.hasNext()) {
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() {
System.out.println(this.name + "....hashCode");
//return 60;
return name.hashCode()+age*37;
}
//复写equals()方法
public boolean equals(Object obj) {
if (!(obj instanceof Person))
return false;
Person p = (Person) obj; // ********
System.out.println(this.name + "...equals.." + p.name);
return this.name.equals(p.name) && this.age == p.age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
2.TreeSet
类的说明:
使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。
保证元素唯一性的依据:
依据compareTo方法的返回值,如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数,返回零,保证元素的唯一。
排序的第一种方式:
让元素自身具备比较性,元素需要实现Comparable接口,覆盖CompareTo()方法,这种方式也称为元素的自然顺序,或者叫做默认顺序。
代码:
import java.util.TreeSet;
import java.util.Iterator;
/*
需求: 往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
TreeSet排序的第一种方式:让元素自身具备比较性。
元素需要实现Comparable接口,覆盖compareTo方法。
也种方式也成为元素的自然顺序,或者叫做默认顺序。*/
class Student implements Comparable//该接口强制让学生具备比较性
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return name;
}
public int getAge()
{
return age;
}
//复写compareTo()方法
public int compareTo(Object obj)
{
//类型判断
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s=(Student)obj;
System.out.println(this.name+".....compareto... "+s.name);
if(this.age>s.age)
{
return 1;
}
if(this.age==s.age)
{
return this.name.compareTo(s.name);
}
return -1;
}
}
class TreeSetDemo {
public static void main(String[] args) {
//创建对象
TreeSet ts=new TreeSet();
//添加内容
ts.add(new Student("lisi02",13));
ts.add(new Student("lisi007",15));
ts.add(new Student("lisi09",18));
ts.add(new Student("lisi08",22));
ts.add(new Student("lisi01",34));
//迭代器 取出集合中的内容
Iterator it=ts.iterator();
while(it.hasNext())
{
Student stu=(Student)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
排序的第二种方式:
当元素自身不具备比较性,或者具备的比较性不是所需要的。
这时需要让容器自身具备比较性。
在集合初始化时,就有了比较方式.
定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
当两种排序都存在时,以比较器为主。
比较器:
定义一个类,实现Comparator接口,覆盖compare方法。
代码:
import java.util.*;
/* 需求:
往TreeSet集合中存储自定义对象学生。
想按照学生的年龄进行排序。
排序的第二种方式:
当元素自身不具备比较性,或者具备的比较性不是所需要的。
这时需要让容器自身具备比较性。
定义比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
当两种排序都存在时,以比较器为主。
比较器:
定义一个类,实现Comparator接口,覆盖compare方法。
*/
class Student implements Comparable// 该接口强制让学生具备比较性
{
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
//复写compareTo()方法
public int compareTo(Object obj) {
// return 0;//保证元素的唯一
if (!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student) obj;
System.out.println(this.name + ".....compareto... " + s.name);
if (this.age > s.age) {
return 1;
}
if (this.age == s.age) {
return this.name.compareTo(s.name);
}
return -1;
}
}
class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<Student>(new MyCompare());
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));
ts.add(new Student("lisi007", 29));
for (Iterator<Student> it = ts.iterator(); it.hasNext();) {
Student s = it.next();
System.out.println(s.getName() + "....." + s.getAge());
}
}
}
八.集合Map
1.接口Map<K,V>:存储键值对。一对一对往里村,并保证元素的唯一性。
2.Map集合常用类;
Hashtable:底层是哈希表数据结构,线程安全,速度慢,不允许存放null键,null值,该集合是线程同步的。效率低,已被HashMap替代。
HashMap:底层是哈希表数据结构,线程不安全,速度快,允许存放null键,null值,该集合是不同步的。效率高,将Hashtable替代。
TreeMap:底层是二叉树数据结构,线程不同步。可以用于给map集合中的键进行排序,排序原理与TreeSet 相同。
Map和Set很像,Set底层就是使用了Map集合。
3.方法:
添加:
put(K key, V value) //将指定的值与此映射中的指定键关联。
putAll(Map<? extends K,? extends V> m) //从指定映射中将所有映射关系复制到此映射中。
删除:
clear() //从此映射中移除所有映射关系。
remove(Object key) //如果存在一个键的映射关系,则将其从此映射中移除。
判断:
containsValue(Object value) //如果此映射将一个或多个键映射到指定值,则返回true。
containsKey(Object key) //如果此映射包含指定键的映射关系,则返回true。
isEmpty() //如果此映射未包含键-值映射关系,则返回 true。
获取:
get(Object key) //返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。
size() //返回此映射中的键-值映射关系数。
values() //返回此映射中包含的值的 Collection 视图。
entrySet() //返回此映射中包含的映射关系的 Set 视图。
keySet()//返回此映射中包含的键的 Set 视图。
代码:
import java.util.*;
class MapDemo {
public static void sop(Object obj)
{
System.out.println(obj);
}
public static void main(String[] args)
{
Map<String,String> map=new HashMap<String,String> ();
//添加元素,添加元素,如果出现添加时,相同的键。那么后添加的值会覆盖原有键对应值。
//并put方法会返回被覆盖的值。
sop(map.put("01", "zhangsan")); //null
sop(map.put("01", "wangwu"));
// map.put("01", "zhangsan");
map.put("02", "liuxiang");
map.put("03", "kb");
map.put("04", "zhanmusi");
sop(map.containsKey("01"));
sop(map.containsValue("lisi"));
map.put("04",null); //map.put(null,"04");
sop(map.get("04"));
//可以通过get方法的返回值来判断一个键是否存在。通过返回null来判断。
//获取map中所有的值
Collection<String> coll=map.values();
sop(coll);
}
}
4. Map集合中取出的两种方式:
取出原理:将map集合转成set集合,在通过迭代器取出。
a. Set<K> keySet():将map集合中的键存入到set集合,通过迭代方式取出所以键的值,再通过get方法。获取每一个键对应的值。
//先获取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);
}
b. Set<Map.Entry<K,V>> entrySet() : 将map集合中的映射关系存入到了set集合中,而这个关系的数据类型就是:Map.Entry。
Entry其实就是Map中的一个static内部接口。
为什么要定义在内部:
因为只有有了Map集合,有了键值对,才会有键值的映射关系。
关系属于Map集合中的一个内部事物。而且该事物在直接访问Map集合中的元素。
代码:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/*
每一个学生都有对应的归属地。
学生Student,地址String。
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。
1,描述学生。
2,定义map容器。将学生作为键,地址作为值。存入。
3,获取map集合中的元素。
*/
class Student implements Comparable<Student>
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
public int compareTo(Student s)
{
int num=new Integer(this.age).compareTo(new Integer(s.age));
if(num==0)
return this.name.compareTo(s.name);
return num;
}
public int ashCode()
{
return name.hashCode()+age*37;
}
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 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);
}
//第二种取出方式 entrySet
Set<Map.Entry<Student,String>> entrySet = hm.entrySet();
Iterator<Map.Entry<Student,String>> iter = entrySet.iterator();
while(iter.hasNext())
{
Map.Entry<Student,String> me = iter.next();
Student stu = me.getKey();
String addr = me.getValue();
System.out.println(stu+"........."+addr);
}
}
}
练习:
"sdfgzxcvasdfxcvdf"获取该字符串中的字母出现的次数。
思路:
1. 将字符串转成字符数组,因为要对每一个字母进行操作
2.定义一个map集合,因为打印结果的字母有顺序,所以使用treemap集合
3.遍历字符数组
将每一个字母作为键去查找map集合
如果返回null,将该字母和1存入到map集合中
如果返回不是null,说明该字母在map集合中已经存在并有对应的次数
那么就获取该次数并进行自增。然后将该字母和自增后的次数存入到map集合中。覆盖调用原理键所对应的值
4.将map集合中的数据变成指定 的字符串形式返回
代码:
class MapTest3 {
public static void main(String[] args) {
String s = charCount("sdfgzxcvasdfxcvdf");
System.out.println(s);
}
public static String charCount(String str) {
//将字符串转换为字符数组
char[] chs = str.toCharArray();
//定义一个TreeMap集合,TreeMap集合会给键自动排序
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();
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 value1 = me.getValue();
sb.append(ch+"("+value1+")");
}
return sb.toString();
}
}
5.Map扩展
一对多的映射关系。
代码:
/*
* map扩展: 一对多的映射关系
* "yureban" "01" "zhangsan"
* "jiuyeban" "01" "Lisi"
* "jiuyeban" "02" "Wangwu"
*
* "yureban" Student("01" "zhangsan")
* "jiuyeban" Student("01" "Lisi")
* "jiuyeban" Student("02" "Wangwu")
* */
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
//抽取共性,定义学生类
class Stu{
private String id;
private String name;
Stu(String id,String name)
{
this.id=id;
this.name=name;
}
public String toString()
{
return id+":"+name;
}
}
class MapDemo3 {
public static void demo()
{
//创建czbk集合
HashMap<String,List<Stu>> czbk=new HashMap<String,List<Stu>>();
//创建班级集合
List<Stu> yure=new ArrayList<Stu> ();
List<Stu> jiuye=new ArrayList<Stu> ();
//关系映射
czbk.put("yureban", yure);
czbk.put("jiuyeban", jiuye);
//添加内容
yure.add(new Stu("01","Zhangsan"));
yure.add(new Stu("02","Lisi"));
jiuye.add(new Stu("01","Wangwu"));
jiuye.add(new Stu("02","LILI"));
//遍历czbk集合,获取所有的教室
Iterator<String> it=czbk.keySet().iterator();
while(it.hasNext())
{
String roomName=it.next();
List<Stu> room=czbk.get(roomName);
System.out.println(roomName);
getInfos(room);
}
}
//定义方法,取出所有的学生对象
public static void getInfos(List<Stu> list)
{
Iterator<Stu> it=list.iterator();
while(it.hasNext())
{
Stu s=it.next();
System.out.println(s);
}
}
public static void main(String[] args) {
//调用方法
demo();
}
}