------- android培训、java培训、期待与您交流! ----------
集合容器顶层接口:Collection。
常用子接口:List、Set:
常用实现类:ArrayList、LinkedList、Vector、HashSet、TreeSet
为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同。
这个存储方式称之为:数据结构。
Collection:
class CollectionDemo{
public static void main(String[] args){
//创建一个集合容器。使用Collection接口的子类。ArrayList
ArrayList al = new ArrayList();
//1,添加元素。
al.add(“java01”);//add(Object obj),参数接收Object,以便于接收任意类型的对象
al.add(“java02”);//集合中存储的都是对象的引用(地址),而不是对象本身。
al.add(“java03”);
al.add(“java04”);
//2,获取个数。集合长度。
sop(“size:”+al.size());
//3,删除元素。
al.remove(“java02”);//删除java02的元素
//al.clear();//清空集合。
//4,判断元素。
sop(“java03是否存在:”+al.contains(“java03”));//判断集合元素是否存在
sop(“集合是否为空?”+al.isEmpty());//判断集合是否为空(也可用size是否为0判断)。
//5,交集
ArrayList al2 = new ArrayList();
al2.add(“java01”);
al2.add(“java02”);
al2.add(“java05”);
al2.add(“java06”);
al.reatainAll(al2);//al中只保留与al2交集的部分元素。
al.removeAll(al2)//al 中去除与al2交集的那部分元素。
Iterator it = al.iterator();//获取迭代器接口Iterator的子类对象,用于取出集合中的元素。
while(it.hasnext()){//循环判断迭代器中是否还有元素
sop(it.next());//打印下一个迭代器中的元素。
}
}
public static void sop(Object obj){
System.out.println(obj)
}
}
迭代器:集合的取出元素的方式。
*每种容器由于其数据结构的差异,所以取出元素的方式都不同,因此每个容器都会在其内部建立一个内部类,用于取出元素。虽然每种容器的取出方式都不同,但是都有共性内部,就是判断和取出,那么可以将这些共性抽取。由此诞生了一个接口,就是Iterator。集合对象通过iterator()方法获取此接口的子类对象。
*下面两段代码的区别:
一:
Iterator it = al.iterator();
while(it.hasNext()){
sop(it.next);
}
二:
for(Iterator it = al.iterator; it.hasNext(); ){
sop(it.next());
}
得到的结果相同,但是第二段代码对内存更加优化,因为it作为for的局部变量,在for循环迭代结束之后就马上被释放。
Collection
|-- List:元素是有序的,元素可以重复。因为该集合体系有索引。
|--Set:元素是无序,元素不可以重复。
List:
特有的方法:凡是可以操作角标的方法都是该体系特有的方法。
增:add(index, element)
addAll(index,Conllection);
删:remove(index);
改:set(index,element);
查:get(index);
sublist(from,to);
listIterator();
class ListDemo{
public static void sop(Object obj){
System.out.println(obj);
}
public static void main(String[] args){
ArrayList al = new ArrayList();
//添加元素
al.add(“java01”);
al.add(“java02”);
al.add(“java03”);}
sop(“原集合是:”+al);
//在指定位置添加元素。
al.add(1,”java09”);
sop(al);
//删除指定位置元素。
al.remove(2);
//修改指定位置的元素。
al.set(2,”java007”);
//通过角标获取元素。
al.get(1);
//获取所有元素。
for(int x=0; x<al.size(); x++){
sop(al.get(x));
}
//通过indexOf获取对象的位置
sop(al.indexOf(“java02”));
//获取子集合
List sub = al.subList(1,3);
sop(“sub=”+sub);
//*列表迭代器listIterator();
//例:在迭代过程中,准备添加或者删除元素。
Object obj = it.next();
if(Obj.equals(“java02”)){
//al.add(“java008”);//正在用迭代器取出的过程中,对集合进行了添加操作,此行为称为并发访问,出现并发修改异常。
it.remove();//使用迭代器自己的去除元素方法,可以正常去除集合元素。
}
sop(“obj=”obj);
//以上的iterator迭代器只有移除元素的功能,出现了局限性,因此诞生了List集合特有的迭代器:ListIterator。
//ListIterator是Iterator的子接口。可以对集合进行添加、修改等操作。
//该接口只能通过List集合的listIterator()方法获得。
ListIterator li = al.listIterator();
while(li.hasNext()){
Object obj = li.next();
if(obj.equals(“java02”)){
li.add(“java009”);
}
}
sop(al);
//ListIterator特性:判断前面是否有元素:li.hasPrevious();
//遍历之后,再往前反向遍历集合:
while(li.hasPrevious()){
sop(li.previous());
}
}
}
List
|--ArrayList:底层的数据结构使用的是数组结构。特点:查询速度很快,但是增删稍慢(元素越多越明显),默认长度为10,超过时50%延长。
|--LinkedList:底层使用的是链表数据结构。特点:增删速度很快,查询稍慢。
|--Vector:底层是数组数据结构。与ArrayList功能基本相同,于jdk1.2版本之前广泛使用(1.2版本后出现ArrayList),特点:Vector是同步的。但是ArrayList线程不同步。多线程时,通常也会使 用ArrayList加锁。因此在1.2版本后,被ArrayList所替代。默认长度为10,超过时100%延长。
Vector特有的东西:枚举
枚举就是Vector特有的取出方式。发现枚举和迭代器很像,其实枚举和迭代时一样的,因为枚举的名称以及方法的名称都过长,所以被迭代器取代了。
class VectorDemo{
public static void main(String[] args){
Vector v = new Vector();
v.add(“java01”);
v.add(“java01”);
v.add(“java01”);
v.add(“java01”);
Enumeration en = v.elements();//此方法可以获得Vector集合的枚举对象。
while(en.hasMoreElements()){
System.out.println(en.nextElement());
}
}
}
LinkedList:
特有方法:addFirst();addLast();getFirst();getLast();removeFirst();removeLast();
class LinkedListDemo(){
public static void sop(Object obj){
System.out.println(obj);
}
public static void main(String[] args){
LinkedList link = new LinkedList();
link.addLast(“java01”);
link.addLast(“java02”);
link.addLast (“java03”);
link.addLast (“java04”);
sop(link.getFirst());//get方法,获取元素,但不删除元素
sop(link.removeFirst());//remove方法,获取元素,但是元素被删除。
sop(link.pollFirst())//jdk1.6版本出现,poll方法,与remove方法功能相同,区别在于当没有元素时,此方法返回null,而remove或者get方法抛出NoSuchElementException异常。
sop(link.peekFirst())//与poll方法类似,为get方法的替代。
sop(link.offerFirst())//与poll方法类似,为add方法的替代。
}
}
*List集合判断元素是否相同,无论是contains()方法还是remove()方法,依据的都是元素的equals()方法。
Set:
|--HashSet:底层数据结构是哈希表。
|--TreeSet:
Set集合的功能和Collection是一致的。
哈希表:对象调用hashcode()方法时返回对象哈希值,当哈希值相同时,再调用equals()方法判断是否是同一个对象。如果哈希值相同、不是一个对象时,会在该地址后顺延,添加此对象。如果哈希值不相同,则将哈希值单独放在一个位置上,不比较是否是同一个对象。
HashSet是通过元素的两个方法来保证元素的唯一性:hashCode和equals。
如果元素的HashCode值相同,才会判断equals是否为true。如果元素的hashhCode值不同,则不会调用equals。
往HashSet集合中存入自定义对象,姓名和年龄相同视为同一个人,重复元素:
class Person{//自定义Person类
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public int hashCode(){
//根据哈希表的数据结构,重写hashCode()方法。
//return 60;//第一种修改方法,将所有被HashSet添加进的元素设置相同的哈希值,就可以调用equals()方法判断是否是相同元素了。
return name.hashCode() + age;//第二种修改方法,由于String类有自己的hashCode()方法,先算出姓名的哈希值与年龄相加作为元素哈希值,再去比较,这样在哈希值判断的层面就把明显的不同元素判断出来,可以省下很多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;
}
}
class HashSetTest{
public static void sop(){
System.out.println(obj);
}
public static void main(String[] args){
HashSet hs = new HashSet();
hs.add(new Person(“a1”, 11));
hs.add(new Person(“a2”, 12));
hs.add(new Person(“a3”, 13));
hs.add(new Person(“a2”, 12));
hs.contains(new Person(“a2”,12));
hs.remove(new Person(“a3”,13);//对于判断元素是否存在以及删除等操作,依赖的方法也是元素的hashCode()和equals()方法。
Iterator it = hs.iterator();
while(it.hasNext()){//遍历集合,查看结果。
Person p = (Person)it.next();
sop(p.getName() + “::”+ p.getAge);
}
}
}
上述代码证实了ArrayList与HashSet的另一处不同:ArrayList判断元素存在以及删除等操作,只依赖equals,而HashSet是先依赖hashCode(),再依赖equals,原因就是数据结构的不同,HashSet的哈希表的特点。