------- android培训、java培训、期待与您交流! ----------
集合框架是为表示和操作集合而规定的一种统一的标准的体系结构。任何集合框架都包含三大块内容:对外的接口、接口的实现和对集合运算的算法。
java集合框架:
1. 什么是框架:类库的集合
2.集合框架:用来表示和操作的统一的架构,包含了实现集合的接口与类
3.集合:存放数据的容器
集合框架包含了两部分:一部分是接口,一部分是类
4.为什么会出现接口:因为集合框架中的很多类 功能是相似的(所以用接口来规范类)
java集合类是一种工具类,用于存储不定长度的数据。Java集合可以大致分为Set,List和Map三种体系,其中Set代表无序、不可重复的集合;List代表有序、重复的集合;而Map代表具有映射关系的集合。从Java5之后又增加了Queue体系集合,代表一种队列集合实现。
集合类的出现是为了在编程时保存数量不确定的数据,以及具有映射关系的数据(也就是关系数组),所以也称集合类为容器类。集合类都位于Java.util包下,为解决线程并发问题Java5之后还在Java.util.concurrent包下提供了支持多线程的集合类。其与数组不一样,数组元素可以保存基本数据类型的值,也可以是对象;而集合类只允许保存对象的引用变量。
Java中的集合类主要有两个接口派生:Collection和Map,Collection和Map是Java集合框架的根接口,这两个接口又包含了一些子接口或实现类。
一:常用集合类之间的层次、继承关系
Collection
|--List:元素是有序的,元素可以重复。因为飞机和体系有索引。
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度快,但是增删稍慢。
|--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。
|--Vector:底层是数组结构,线程同步,被ArrayList替代了,因为效率低。
|--Set:元素是无序的(存入和取出的顺序不一定一致),元素不可以重复。
|--HashSet:底层数据结构是哈希表。HashSet通过hashCode和equals判断元素是否重复。如果元素的hashCode值相同,才会判断equals是否为true。如果元素的hashCode值不同,不会调用equals。对于判断元素是否存在,以及删除等操作依赖的方法是元素的hashCode和equals方法。
|--LinkedSet:通过hashcode确定元素的存储位置,同时通过链表确定元素的顺序。
|--TreeSet:可以对Set集合中的元素进行排序,底层数据结构是二叉树。它保证元素唯一性的依据是compareTo方法的return。TreeSet默认顺序采用的是红黑树。TreeSet允许自定义排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需的,这是就需要让集合自身具备比较性,在集合初始化时就让其具有比较性方式。
|--EnumSet:专门为枚举类设计的集合类,其中所有的元素都必须是指定枚举类型的枚举值,该枚举类型在创建EnumSet时显式或隐式的指定。EnumSet的集合元素也是有序的,EnumSet以枚举值在Enum内部的定义顺序来决定集合元素的顺序。
|--Map:用于保存具有映射关系的数据。
|--HashMap:底层数据结构是哈希表。HashMap通过hashCode和equals判断元素是否重复。如果元素的hashCode值相同,才会判断equals是否为true。如果元素的hashCode值不同,不会调用equals。
|--TreeMap:可以对Map集合中的元素进行排序,底层数据结构是二叉树。它保证元素唯一性的依据是compareTo方法的return。TreeSet默认顺序采用的是红黑树。TreeSet允许自定义排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需的,这是就需要让集合自身具备比较性,在集合初始化时就让其具有比较性方式。
|--EnumMap:与枚举类一起使用的Map实现,EnumMap中的所有KEY都必须是单个枚举类的枚举值。创建EnumMap的时候必须显式或隐式的指定它对应的枚举类。
|--Queue:用于模拟队列这种数据结构,不允许随机访问。
|--PriorityQueue:数据的存储不按照加入队列的顺序,而是按照队列元素的大小重新排序。因此,当取出队列元素时,取出的并不是最先加入队列元素而是最小的元素。
|--ArrayQueue:基于数组实现的是双端队列。
List:
特有方法,凡是可以操作角标的方法都是该体系特有的方法
增
add(intindex,Eelement);
addAll(index,Collection);
删
remove(index);
改
set(index,element);
查
get(index);
subList(form,to);
listIterator();
List集合特有的迭代器,ListIterator是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素
因为会发生ConcurrentModificationException并发操作异常
所以,在迭代时,只能用迭代器的方法操作元素,可以Iterator方法是有限的
只能对元素进行判断,取出和删除的操作
如果想要其他的操作如添加,修改等,就需要使用其子接口ListIterator
该接口只能通过List集合listIterator方法获取
import java.util.*;
/*
1.add方法的参数类型是Object,以便于接受任意类型对象
2.方法中存储的都是对象的引用或者地址
什么是迭代器呢?
其实就是集合的取出元素的方式
*/
class CollectionDemo {
publicstatic void main(String[] args) {
//method_2();
//base_method();
get_method();
}
publicstatic void sop(Object obj) {
System.out.println(obj);
}
publicstatic void base_method() {
//创建一个集合容器,使用Collection接口的子类:ArrayList
ArrayListal = new ArrayList();
//1,添加元素
al.add("java01");//add()参数类型是Object类型的,因为可以是任意对象
al.add("java02");
al.add("java03");
al.add(4);
sop("原集合:" + al);
//2.获取个数,集合长度size();
sop("size="+ al.size());
//3.删除元素
al.remove("java02");
sop("改变后的集合:" + al);
al.clear();//清空集合
sop(al);
//4.判断集合是否为空
sop("判断元素是否存在" + al.contains("java01"));
sop("判断集合是否为空" + al.isEmpty());
}
publicstatic void method_2() {
ArrayListal1 = new ArrayList();
al1.add("java01");//add()参数类型是Object类型的,因为可以是任意对象
al1.add("java02");
al1.add("java03");
ArrayListal2 = new ArrayList();
al2.add("java05");//add()参数类型是Object类型的,因为可以是任意对象
al2.add("java06");
al2.add("java04");
al2.retainAll(al1);//取交集,al1中只会保留和al2中相同的元素
sop("al1:"+ al1);
sop("al2:"+ al2);
}
publicstatic void get_method() {
ArrayListal = new ArrayList();
al.add("java01");
al.add("java02");
al.add("java03");
al.add(4);
/*
* Iterator it = al.iterator();//返回的是Iterator接口类型的对象,Iterator是一个集合的内部类
* while (it.hasNext()) { sop(it.next()); }
*/
for(Iterator it = al.iterator(); it.hasNext();)// 这样写不用在迭代结束后还保留it对象,因为it是for循环的一个内部变量,便于内存管理
{
sop(it.next());
}
}
}
import java.util.*;
class ListDemo {
publicstatic void main(String[] args) {
//method();
//演示列表迭代器
ArrayListal = new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add(4);
sop("原集合是:" + al);
ListIteratorli = al.listIterator();
while(li.hasNext()) {
Objectobj = li.next();
if(obj.equals("java02"))
li.set("java006");
if(obj.equals("java03"))
li.add("new");
sop("obj="+ obj);
}
sop(li.hasNext());
sop(li.hasPrevious());
sop("改变后的集合:" + al);
//在迭代过程中,准备添加或者删除元素
/*
* Iterator it = al.iterator(); while(it.hasNext()) { Object obj =
* it.next(); if(obj.equals("java02"))
* //al.add("java008");//这步操作可能会引起并发访问异常,因为al有两种操作方式,容易产生安全隐患
* it.remove();
* sop("obj="+obj);//迭代过程中即使删除的元素也会被obj引用,所以也能打印出来,而且Iterator只有三个方法,有局限性
* }
*/
}
publicstatic void method() {
ArrayListal = new ArrayList();
//添加元素
al.add("java01");
al.add("java02");
al.add("java03");
al.add(4);
sop("原集合是:" + al);
//在指定位置添加元素
al.add(1,"java09");
//删除指定位置的元素
//all.remove(2);
//修改元素
al.set(2,"java007");
//通过角标获取元素
//sop("get(1):"+al.get(1));
//sop(al);
//获取所有元素
for(int x = 0; x < al.size(); x++) {
sop("al("+ x + ")=" + al.get(x));
}
Iteratorit = al.iterator();
while(it.hasNext()) {
sop(it.next());
}
//通过indexOf获取对象的位置
sop("index="+ al.indexOf("java09"));
Listsub = al.subList(1, 4);
sop("sub="+ sub);
}
publicstatic void sop(Object obj) {
System.out.println(obj);
}
}
import java.util.*;
/*
LinkedList:特有方法
addFist();
addLast();
getFirst();
getLast();
removeFirst();
removeFirst();
JDK1.6以后出现了替代方法:
offerFirst();
offerFirst();
peekFirst();
peekLast();如果没有元素,则返回null
pollFirst();
pollLast();如果没有元素,则返回null
*/
class LinkedDemo {
publicstatic void main(String[] args) {
LinkedListlink = new LinkedList();
link.addFirst("java01");
link.addFirst("java02");
link.addFirst("java03");
link.addFirst("java04");
sop(link);
sop(link.getFirst());
sop(link.getLast());
sop(link.size());
sop(link.removeFirst());
sop(link.size());
while(!link.isEmpty()) {
sop(link.removeFirst());
}
}
publicstatic void sop(Object obj) {
System.out.println(obj);
}
}
Map集合:该集合存储键值对一对一对往里存而且要保证键的唯一性
1.添加
put(Kkey,Vvalue)
putAll(Map<?extendsK,?extendsV>m)
2.删除
clear()
remove(Objectkey)
3.判断
containsKey(Objectvalue)
containsValue(Objectvalue)
isEmpty()
4.获取
size()
values()
get(Objectkey)
keySet()
entrySet()
Set:无序,不可以重复元素
--HashSet:数据结构是哈希表,线程是非同步的
保证元素唯一性的原理,判断元素的hashCode值是否相同
如果相同,还会继续判断元素的equals方法,是否为true
--TreeSet:可以对Set集合中的元素进行排序
底层数据结构是二叉树
1,保证元素唯一性的依据compareTo方法return0。
2,当元素不具备比较性时,或者具备的比较性不是所需要的
这时就需要让集合自身具备比较性
在集合初始化时,就有了比较方式
需求;
往TreeSet集合中存储自定义对象学生
想按照学生的年龄进行排序
记住:排序时,当主要条件相同时,一定判断次要条件
import java.util.*;
class TreeSetDemo {
publicstatic void main(String[] args) {
TreeSetts = new TreeSet();
ts.add(newStudent("lisi02", 22));
ts.add(newStudent("lisi007", 20));
ts.add(newStudent("lisi09", 19));
ts.add(newStudent("lisi08", 19));
Iteratorit = ts.iterator();
while(it.hasNext()) {
Studentstu = (Student) it.next();
System.out.println(stu.getName()+ "::" + stu.getAge());
}
}
}
class Student implements Comparable// 该接口强制让学生具备比较性
{
privateString name;
privateint age;
Student(Stringname, int age) {
this.name= name;
this.age= age;
}
publicint compareTo(Object obj) {
if(!(obj instanceof Student))
thrownew RuntimeException("不是学生对象");
Students = (Student) obj;
System.out.println(this.name+ "::compare to::" + s.name);
if(this.age > s.age)
return1;
if(this.age == s.age) {
returnthis.name.compareTo(s.name);
}
;
return-1;
}
publicString getName() {
returnname;
}
publicint getAge() {
returnage;
}
}
Map
Hashtable:底层是哈希表数据结构,不可以存入null键null值,该集合是线程同步的
HashMap:底层是哈希表数据结构允许使用null值和null键该集合是不同步的
TreeMap:底层是二叉树数据结构,线程不同步,可以用于给Map集合中的键进行排序
和Set很像
Set底层就是使用了Map集合
map集合的两种取出方式
1.Ser<k>keySet:将map中所有的键存入到Set集合,因为Set集合具备迭代器,
所以可以用迭代方式取出所有的键,再根据ger方法,获取每一个键对应的值
Map集合的取出原理:将map集合转换成set集合再通过迭代器取出
import java.util.*;
public class MapDemo2 {
publicstatic void main(String[] args) {
Map<String,String> map = new HashMap<String, String>();
map.put("02","zhangshan02");
map.put("03","zhangshan03");
map.put("01","zhangshan01");
map.put("04","zhangshan04");
//先获取map集合的所有键的Set集合,keySet();
Set<String>keySet = map.keySet();
//有了Set集合,就可以获取其迭代器
Iterator<String>it = keySet.iterator();
while(it.hasNext()) {
Stringkey = it.next();
//有了键可以通过map集合的get方法获取其对应的值
Stringvalue = map.get(key);
System.out.println("key--"+ key + ",value" + value);
}
}
}
2.Ser<Map.Entry<k,v>>entrySet:将map集合中的映射关系存入到了set集合中,
而这个关系的数据类型就是:Map.Entry
对于HashSet和TreeSet它们的排序是如何进行的呢?
覆盖compareTo的方法
TreeSet 是否用的二叉树算法插入数据?
hashcode()与 equals()
hashcode 重写一般只有用于集合的时候才有用
equals() 则是判断调用方法
HashSe 与 TreeSet 类示例
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;
public class HashSetTest {
publicstatic void main(String[] args) {
Perp1 = new Per(12);
p1.idCard= "1";
Perp2 = new Per(33);
p2.idCard= "1";
HashSet<Per>hs = new HashSet<Per>();
hs.add(p1);
hs.add(p2);
p2.idCard= "3";
System.out.println(hs.size());
Iterator<Per>it = hs.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
Perp3 = new Per(22);
Perp4 = new Per(15);
Perp5 = new Per(17);
//实现 Comparator接口 设置排序方式
TreeSet<Per>ts = new TreeSet<Per>(new Comparator<Per>() {
@Override
publicint compare(Per o1, Per o2) {
//TODO Auto-generated method stub
returno1.age - o2.age;
}
});
ts.add(p1);
ts.add(p2);
ts.add(p3);
ts.add(p4);
ts.add(p5);
System.out.println(ts.size());
Iterator<Per>it2 = ts.iterator();
while(it2.hasNext()) {
System.out.println(it2.next());
}
}
}
class Per {
StringidCard;
Stringname;
intage;
publicPer() {
}
publicPer(int age) {
this.age= age;
}
@Override
publicint hashCode() {
finalint prime = 31;
intresult = 1;
result= prime * result + ((idCard == null) ? 0 : idCard.hashCode());
returnresult;
}
@Override
publicboolean equals(Object obj) {
if(this == obj)
returntrue;
if(obj == null)
returnfalse;
if(getClass() != obj.getClass())
returnfalse;
Perother = (Per) obj;
if(idCard == null) {
if(other.idCard != null)
returnfalse;
}else if (!idCard.equals(other.idCard))
returnfalse;
returntrue;
}
@Override
publicString toString() {
return"Per [idCard=" + idCard + ", name=" + name + ",age=" + age + "]";
}
}
集合框架中的工具类
Collections
对集合进行查找
取出集合中的最大值,最小值
对List集合进行排序
……
Arrays
将数组转成List集合
对数组进行排序
public static void main(String[] args){
char[] c = new char[]{'A','c','B','d','E'};
int[] b = new int[]{1,32,22,11,35,21,9,8};
//如果数组类型是基本类型数组 则转成的list集合 没有数据 因为无法对基本类型进行泛型
List ls = Arrays.asList(c); //转换成list 集合
System.out.println(ls.size());
Arrays.sort(c); //排序
System.out.println(Arrays.toString(c));
Arrays.sort(b);
int i = Arrays.binarySearch(b,35);; //使用二分法查找 必须先排序 才可以查找该元素
System.out.println(Arrays.toString(b));
System.out.println(i);
}
1、两个对象值相同(x.equals(y)==true),但却可有不同的hashcode,这句话对不对?
对。
如果对象要保存在HashSet或HashMap中,它们的equals相等,那么,它们的hashcode值就必须相等。
如果不是要保存在HashSet或HashMap,则与hashcode没有什么关系了,这时候hashcode不等是可以的,例如arrayList存储的对象就不用实现hashcode,当然,我们没有理由不实现,通常都会去实现的。
2、TreeSet里面放对象,如果同时放入了父类和子类的实例对象,那比较时使用的是父类的compareTo方法,还是使用的子类的compareTo方法,还是抛异常?
public class Parent implementsComparable {
privateint age = 0;
publicParent(int age){
this.age= age;
}
publicint compareTo(Object o) {
//TODO Auto-generated method stub
System.out.println("methodof parent");
Parento1 = (Parent)o;
returnage>o1.age?1:age<o1.age?-1:0;
}
}
public class Child extends Parent {
publicChild(){
super(3);
}
publicint compareTo(Object o) {
//TODO Auto-generated method stub
System.out.println("methodof child");
// Childo1 = (Child)o;
return1;
}
}
public class TreeSetTest {
/**
* @param args
*/
publicstatic void main(String[] args) {
//TODO Auto-generated method stub
TreeSetset = new TreeSet();
set.add(newParent(3));
set.add(newChild());
set.add(newParent(4));
System.out.println(set.size());
}
}