集合框架
集合和数组的区别:
| 集合 | 数组 |
长度 | 可变的 | 固定的 |
存储的对象 | 可以存储不同类型的对象(只能存对象) | 只能存同一种对象、可以存储基本数据类型 |
都是容器 |
为什么会出现这么多的容器呢?
因为每一个容器存储数据的方式都不同。存储方式就叫做数据结构。
Collection中的共性方法:
add();添加元素。
addAll(Collection c);添加一组元素,将另一个容器的元素全添加进来。
clear();清空容器。
contains();判断容器中是否包含某元素,返回值为boolean。
isEmpty();判断容器是否为空。返回boolean。
remove();移除容器中的某元素。
removeAll(Collection c);移除容器中和c容器的交集。改变原容器元素,并不是返回新容器。
retainAll(Collection c);保留容器中和c容器的交集。改变原容器元素,并不是返回新容器。
size();获取容器的长度。
集合容器中存储的是对象的地址,不是实体。
对集合容器中元素的取出用迭代器:
ArrayList al = new ArrayList();//定义一个集合,并添加两个元素。
al.add("heima01");
al.add("heima02");
Iterator it = al.iterator();//al.iterator返回的是一个对象,并被Iterator接口引用
while(it.hasNext()){
//it.hasNext是通过hasNext方法来判断所指对象中的元素是否存在,存在则返回true。
System.out.println(it.next());//it.next则是取出存在的元素。
}
List集合与Set集合的异同:
List:元素是有序的,元素可以重复,元素有索引。可以操作脚标的就是List。
Set:元素是无序的,元素不可以重复。
List集合的特有方法:
1、add(index,element):在脚标index处添加element元素。
2、addAll(index,Collection):在脚标index处添加一组元素。
3、remove(index):删除index脚标处的元素。
4、set(index,element):修改index脚标处的元素,改成element。
5、get(index):获取index脚标处的元素。
6、subList(from,to):获取从from脚标到to脚标的元素,包含头不含尾。
7、listIterator():迭代器。
在用Iterator迭代器迭代时,不可以通过集合对象的方法操作集合中的元素,也就是说,不可以一边迭代一边用集合对象方法操作元素,包含添加、修改等操作,可以用Iterator的remove方法移除操作。要不然的话,会发生ConcurrentModificationException异常。
要想一边迭代,一边作添加,修改等操作,就用ListIterator。其方法是Iterator的子接口,方法比Iterator多,其中有:
hasPrevious():返向遍历,和hasNext()相反。
previous():返回列表中前一个元素,和next()相反。
remove():移除当前迭代到的元素。
set():修改当前迭代到的元素。
List集合的三个小弟的特点:
1、ArrayList:数组结构。特点:查询速度快,增删稍慢。线程不同步。1.2版本出现的。
2、LinkedList:链表结构。特点:查询速度慢,增删快。
3、Vector:数组结构。无论增删查询都慢。和ArrayList的功能一样,不同之处是线程同步,1.0版本就有了。被ArrayList替代了,遇到多线程,自己加锁。
Vector中特有的取出方式:枚举。
1、枚举和迭代器是一样的。
2、枚举被失代器取代了。
LinkedList的特有方法:
offerFirst():添加元素到起始位置。 **1.6版本以前是:addFirst();
offerLast():添加元素到末尾位置。 **1.6版本以前是:addLast();
peekFirst():获取起始位置的元素,不删除,如果没有元素,返回null。 **1.6版本以前是:getFisrt();
peekLast():获取末尾位置的元素,不删除,如果没有元素,返回null。 **1.6版本以前是:getLast();
pollFirst():获取起始位置的元素,同时删除,如果没有元素,返回null。 **1.6版本以前是:removeFirst();
pollLast():获取末尾位置的元素,同时删除,如果没有元素,返回null。 **1.6版本以前是:removeLast();
练习:除集合中的重复自定义元素
/*
去除集合中的重复的自定义元素。
*/
import java.util.ArrayList;
import java.util.Iterator;
public class LinkedTest_03 {
public static void main(String[] args) {
ArrayList al = new ArrayList(); //定义ArrayList集合
//向al集合中存入Person元素,其中有相同的元素。
al.add(new Person("樊波",28));
al.add(new Person("樊波",28));
al.add(new Person("向波",27));
al.add(new Person("樊波",28));
al.add(new Person("张明照",40));
al.add(new Person("黄权",29));
al.add(new Person("黄权",29));
al.add(new Person("向波",27));
al.add(new Person("罗练",25));
al = xiaoChong(al); //将al消重。
//打印消重后的al元素。
Iterator it = al.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
System.out.println("姓名:"+p.getName()+" "+"年龄:"+p.getAge());
}
}
//消重方法。
publicstatic ArrayList xiaoChong(ArrayList arr){
ArrayList newal = new ArrayList();
Iterator it = arr.iterator();
while(it.hasNext()){
Object obj = it.next();
//判断参数集合的元素,是否在新集合中存在,不存在,则存入新集合中。
if(!newal.contains(obj))
newal.add(obj);
}
return newal;//返回消重后的新集合。
}
}
//自定义Person类,并写覆写Object中的equals方法,实现自己的比较方式。姓名和年龄都相同,则为同一个人。
class Person{
private Stringname;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
returnname;
}
publicint getAge(){
return age;
}
publicboolean equals(Object obj){
if(!(objinstanceof Person))
returnfalse;
Person p = (Person)obj;
returnthis.name.equals(p.name) &&this.age==p.age;
}
}
注:contains和remove底层用的都是equals。
在开发中,如果存储的元素较多,涉及到增删比较多,用LinkeList,如果对存储的数据查询比较频繁,用ArrayList,ArrayList在开发中用得最多。
HashSet:
HashSet是如何保证元素的唯一性的呢?
是通过元素的两个方法,hashCode和equals来完成。
如果元素的HashCode值相同,才判断equals是否为true。
如果元素的hashCode值不同,不会调用equals。
注意:
HashSet判断元素是否存在,以及删除等操作,先依赖hasCode,再依赖equals方法。
ArrayList判断元素是否存在,只依赖equals方法。
TreeSet:
可以对Set集合中的元素进行排序。往TreeSet集合存对象,这个对象必须具备比较性。
练习:用TreeSet存储自定义对象,并用指定方式排序。
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetTest {
publicstatic void main(String[] args) {
TreeSet ts = new TreeSet();//创建TreeSet集合
//向集合中添加Student对象,其中有相同元素。
ts.add(new Student("樊波",25));
ts.add(new Student("向波",24));
ts.add(new Student("樊b波",21));
ts.add(new Student("樊a波",20));
ts.add(new Student("樊波",25));
//迭代打印出Student对象的属性。
Iterator it = ts.iterator();
while(it.hasNext()){
Student p = (Student)it.next();
System.out.println(p.getName()+" "+p.getAge());
}
}
}
//创建Student类,并实现Comparable接口,并覆盖compareTo方法,方法中定义自定义的比较方式,先按性名排序,再按年龄排。
class Studentimplements Comparable{
private Stringname;
privateint age;
Student(String name, int age){
this.name = name;
this.age = age;
}
public String getName(){
returnname;
}
publicint getAge(){
returnage;
}
public int compareTo(Object obj){
if(!(objinstanceof Student))
thrownew RuntimeException("不是人这个对象");
Student p = (Student)obj;
if((this.name.compareTo(p.name))>0)
return 1;
if(this.name.compareTo(p.name)==0){
if(this.age>p.age)
return 1;
if(this.age<p.age)
return -1;
return 0;
}
return -1;
}
}
Map集合:
存储键值对,一对一对的存,而且要保证键的唯一性。
键不可以重复,值可以重复。存值的时候,如果重复了键,那么第二次存的键值覆盖前一次存的键值。
其共性方法:
1、添加:
put(key,value):一对一对存储。如果添加时,相同的键,那么后添加的值会覆盖原有键对应的值,并put方法会返回被覆盖的值。
putAll():一次存一堆。
2、删除:
clear():清空。
remove(key):通过键来删除元素。
3、判断:
containsValue(value):
containsKey(key):
isEmpty():是否为空。
4、获取:
get(key):通过键获取元素。可以通过get方的的返回值来判断一个键是否存在,通过返回null来判断。
size():
values():返回的是一个Collection集合,获取Map里面的所有值。
keySet():将map中的所有的键取出存到Set集合中,Set集合具备迭代器,所以可通过过迭代取出所有的键,再根据get方法,获取每个键对应的值。
例如:
package CollectionTest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest {
publicstatic void main(String[] args) {
//定义一个Map集合。
Map<String,String> map = new HashMap<String,String>();
//向集合中存入5个键值对元素。
map.put("fan01", "fan bo1");
map.put("fan02", "fan bo2");
map.put("fan04", "fan bo4");
map.put("fan03", "fan bo3");
map.put("fan05", null);
//用keySet方法将Map集合中的键取出来,并存入到Set集合中。
Set<String> set = map.keySet();
//迭代取出Set集合中的Ket,并用get方法获得键对应的值。
Iterator<String> it = set.iterator();
while(it.hasNext()){
String str = it.next();
System.out.println("Key:"+str+" Value:"+map.get(str));
}
entrySet():
返回的类型为:Set<Map.Entry<k,v>>返回的是Set集合,类型为Map.Entry<k,v>
将Map集合中的映射关系存入到Set集合中,而这个关系的数据类型就是:Map.Entry。存入到Set集合了,就可以用迭代器了。
例如:
public class MapTest {
public static void main(String[]args) {
//定义一个Map集合。
Map<String,String> map =new HashMap<String,String>();
//向集合中存入5个键值对元素。
map.put("fan01", "fan bo1");
map.put("fan02", "fan bo2");
map.put("fan04", "fan bo4");
map.put("fan03", "fan bo3");
map.put("fan05", null);
//通过entrySet方法将Map集合的键值关系存入到Set集合中。
Set<Map.Entry<String,String>>set = map.entrySet();
//迭代取出Set集合中的关系元素。
Iterator<Map.Entry<String,String>> it = set.iterator();
while(it.hasNext()){
Map.Entry<String,String>me = it.next();
//再通过getKey和getValue方法获得Map里面的键和值。
Stringkey = me.getKey();
Stringvalue = me.getValue();
System.out.println("Key:"+key+" Value:"+value);
}
}
}
Hashtable:底层是哈希表数据结构,不可以存入null键和null值,线程同步的,效率低。
HashMap:底层是哈希表数据结构,允许使用null键和null值,线程不同步的,效率高。
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序。
Map集合和Set集合很像,Set底层就是用了Map集合。
Map里面没有迭代器。
练习:
/*
* 自定义一个SuperPerson类,并将此类作为键,地址作为值,存入HashMap中。
* 定义SuperPerson类时,让元素具备可比性。
* */
package CollectionTest;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
public class HashMapTest {
public static void main(String[] args) {
//定义TreeMap集合,并将SuperPerson作为键,地址作为值。
TreeMap<SuperPerson,String> tm = newTreeMap<SuperPerson,String>();
//向TreeMap集合中存入元素。
tm.put(new SuperPerson("fanbo",25),"月波");
tm.put(new SuperPerson("xianbo",20),"越溪");
tm.put(new SuperPerson("huangquan",14),"商州");
tm.put(new SuperPerson("zhouyifei",28),"北京");
tm.put(new SuperPerson("heweichao",25),"湖南");
tm.put(new SuperPerson("heweichao",25),"湖南");
/*
//第一种取出方式:keySet()
Set<SuperPerson> set = hm.keySet();
Iterator<SuperPerson> it = set.iterator();
while(it.hasNext()){
SuperPerson sp = it.next();
String value = hm.get(sp);
System.out.println(sp.getName()+" "+sp.getAge()+" "+value);
}
*/
//第二种取出方式:entrySet()
Set<Map.Entry<SuperPerson,String>> me =tm.entrySet();
Iterator<Map.Entry<SuperPerson,String>> iter =me.iterator();
while(iter.hasNext()){
Map.Entry<SuperPerson, String> ME = iter.next();
SuperPerson SP = ME.getKey();
String VALUE = ME.getValue();
System.out.println(SP.getName()+" "+SP.getAge()+" "+VALUE);
}
}
}
//定义SuperPerson类,并实现Comparable接口。
class SuperPersonimplements Comparable<SuperPerson>{
private Stringname;
private int age;
SuperPerson(String name,int age){
this.name = name;
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//覆盖hashCode()方法。
public int hashCode(){
return name.hashCode()+age*33;
}
//覆盖equals方法。
public boolean equals(Object obj){
if(!(objinstanceof SuperPerson))
throw new RuntimeException("对象存错了。");
SuperPerson sp = (SuperPerson)obj;
return this.name.equals(sp.getName()) &&this.age == sp.getAge();
}
//覆盖Comparable接口中的compareTo方法。
public int compareTo(SuperPerson sp1){
int num =this.age-sp1.getAge();
if(num == 0)
return this.name.compareTo(sp1.getName());
return num;
}
}
集合框架工具类:
Collections:里面的方法全静态的。对集合进行操作。
sort(List<T>list):对list集合进行排序。它不能给Set排序。
sort(List<T>list,Comparator c):可以传入自定义比较器,按指定的规则进行比较。
max(List<T>list):获取一堆元素中的最大元素。
max(List<T> list, Comparator c):获取按指定顺序排序后的最大元素。
binarySearch(List<T>l,T):二分法查找集合中的某元素,但凡用此方法,必须是有序集合。返回的是T元素的脚标,如果T不存在,则返回T应该在集合中的脚标的负数-1。
fill(List<T> list,T):将集合中的所有元素全替换成T元素。
replaceAll(List<T> list,T1,T2):T2元素替换T1元素.
reverse(List<T> list):反转。将集合中所有元素反转一下。
SynList():
reverseOrder():返回的是一个比较器,传入此比较器后,强行逆转集合中的元素。
reverseOrder(Comparable c):返回的还是一个比较器,比较器里再传入一个比较器,就是按参数比较之后,再强行逆转元素。
synchronizedCollection(Collection<T> c):传入一个不同步的集合,返回一个同步的集合。
swap(List<T> list,int i,int j):无返回值,将集合中脚标为i和j的元素交换位置。
shuffle(List<T> list):无返回值,随机的对集合中元素进行置换。(扑克牌)
示例:
Collections.sort(list);//排序,返回排序后的集合。
Collections.sort(list,newMyComp());//传入自定义比较器,自定义排序。
String str = Collections.max(list);//获取集合元素中的最大值,返回元素。
String str = Collections.max(list,new MyComp());//获取指定排序后的最大元素,反回元素。
int i =Collections.binarySearch(list,"cfjas");//返回指定元素在集合中的脚标。
Collections.fill(list,"ttttt");//把list中的所有元素,替换成“tttt”。
Collections.replaceAll(list,"aajs", "fanbo");//将aajs替换成fanbo。
Collections.reverse(list);//反转集合中的元素。
Collections.sort(list,Collections.reverseOrder());//强行逆转集合中元素的比较器。
Collections.swap(list, 2, 3);//将2、3位置的元素交换一下位置。
Collections.shuffle(list);//将集合中的元素随机的置换位置。
Arrays:
用于操作数组的工具类。里面也全是静态方法。
asList(Array[]arr):将数组变成List集合。好处:可以使用集合的思想和方法,来操作数组中的元素。
注意:将数组变成集合,不可以使用集合的增删方法,因为数组的长度是固定的。可以使用contains、get、indexOf、subList等等方法,如果增删,会发生不支持异常。
如果数组中的元素都是对象,那么变成集合时,数组中的元素就直接转成集合中的元素。如果数组中的元素都是基本数据类型,那么会将该数组作为集合中的元素存在。
Arrays中还有binarySearch、copyOf、deepToString、equals、fill、sort、toString等等方法。
集合变成数组:
toArray():
toArray(T[]a):返回T类型的数组。
1、集合是可变长度的,数组是固定长度的,集合变成数组,得定义多大长度数组呢?
当指定类型的数组长度小于集合的size时,那么该方法内部会创建一个新的数组,长度为集合的size。
当指定类型的数组长度大于集合的size时,就不会新创建数组了,而是使用传递进来的数组。
所以创建一个刚刚好的数组最优。如:String[] arr = list.toArray(new String[list.size])。
2、为什么要将集合变成数组?
为了限定对元素的操作,不需要进行增删了。