集合类
定义:为了方便对多个对象的操作,就对对象进行存储,集合就是其中的一种方式
集合和数组的不同之处:
1,数组是固定长度的,集合是可变长度的
2,数组可以储存基本数据类型和引用型数据类型,集合只能存储引用数据类型
3,数据存储的元素必然是统一个数据类型,集合存储的对象是不同数据类型
数据结构:
数据结构就是容器中存储数据的方式,对于集合容器,有很多种。因为每一个容器的自身特点不同,其实原理在于每个容器的内部数据结构不同。
集合容器在不断向上抽取过程中。出现了集合体系。
集合框架结构图:
------------------------------------------------------------------------------------------------------------------
Collection接口
|--List:有序(元素存入集合的顺序和取出的顺序一致),元素都有索引。元素可以重复。
|--Set:无序(存入和取出顺序有可能不一致),不可以存储重复元素。必须保证元素唯一性
提供的方法:
1,添加:
add(E a) 确保此collection包含指定的元素
addAll(Collection<? extends E>c)将指定collection中的所有元素都添加到此collection中。
2,删除
clear()将集合中的元素全删除,即清空集合
remove(Object o)从此collection中移除指定元素的单个实例,如果存在的话,注意:删除成功,集合的长度会改变。
removeAll(Collection<?>c)移除此collection中那些也包含在指定collection中的所有元素
3,判断
boolean isEmpty()如果此collection不包含元素,则返回true
4,获取
boolean contains(obj) :集合中是否包含指定元素 。
boolean containsAll(Collection) :集合中是否包含指定的多个元素。
int size() 返回此collection中的元素数
5,取交集
boolean retainAll(Collection<?>c)仅保留此collection中那些也包含在指定collection的元素。集合和数组一样,里面存的都是地址。
6,获取集合中所有元素:
Iterator iterator()返回在此collection的元素上进行迭代的迭代器
7,将集合变成数组:
toArray()返回包含此collection中所有元素的数组
toArray(T[]a)返回包含此collection中所有元素的数组,返回数组的运行时类型与指定数组的运行时类型相同。
hashCode()返回此collection的哈希码值。
注意:集合里存储的是应用地址
--------------------------------------------------------------------------------------------------------------------------
Iterator接口
迭代器:
其实就是集合的取出元素的方式,就把取出方式定义在集合的内部,这样取出方式就可以直接访问集合内部的元素,那么取出方式就被定义成了内部类,而每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容,判断和取出,那么可以将这些共性抽取,那么这个内部类都符合一个规则,该规则是Iterator。
方法:
1,boolean hasNext():如果仍有元素可以迭代,则返回true.
2,next():返回迭代的下一个元素
3,void remove():从迭代器指向的collection中移除迭代器返回的最后一个元素
Iterator it = coll.iterator();//获取容器中的迭代器对象,至于这个对象是是什么不重要。这对象肯定符合一个规则Iterator接口。
- import java.util.*;
- public class collectionDemo {
- public static void main(String[] args) {
- method();
- }
- public static void method_get()
- {
- //创建一个集合容器,使用collection接口的子类。ArrayList
- ArrayList a1=new ArrayList();
- a1.add("java01");
- a1.add("java03");
- /**Iterator it=a1.iterator();//获取迭代器,用于取出集合中的元素
- while(it.hasNext());
- {
- sop(it.next());
- }//写for更优些。it是局部变量,用完就释放。而while中就没释放。
- */
- for(Iterator it=a1.iterator();it.hasNext();)
- {
- sop(it.next());
- }
- }
- public static void method()
- {
- //创建一个集合容器,使用collection接口的子类。ArrayList
- ArrayList a1=new ArrayList();
- //1.添加元素
- a1.add("java01");//add(Object obj)
- a1.add("java03");
- ArrayList a2=new ArrayList();
- //1.添加元素
- a2.add("java01");//add(Object obj)
- a2.add("java02");
- a1.retainAll(a2);//取交集,a1中只会保留和a2中相同的元素
- a1.removeAll(a2);//移除与a2中相同的元素。
- sop("a1:"+a1);
- sop("a2:"+a2);
- }
- public static void base_method()
- { //创建一个集合容器,使用collection接口的子类。ArrayList
- ArrayList a1=new ArrayList();
- //1.添加元素
- a1.add("java01");//add(Object obj)
- a1.add("java02");
- //打印集合
- sop(a1);
- //2.获取个数,集合长度
- sop("size:"+a1.size());
- //3.删除元素
- a1.remove("java02");
- a1.clear();//清空集合
- //打印改变后的集合
- sop(a1);
- //4判断元素
- sop("java03是否存在"+a1.contains("java03"));
- sop("集合是否为空?"+a1.isEmpty());
- }
- public static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
List接口
| --ArrayList:底层的数据结构使用的是数组结构,特点:查询速度快。但是增删稍慢。线程不同步。50%延长,是 1.2版线程不同步。它默认的长度10元素,超出时,以50%延长
|--LinkedList:底层使用的是链表数据结构。特点:增删速度快,查询稍慢
|--Vector:底层是数组数据结构。1.0版,是同步的。被arrayList替代了。长度为10,长度百分百延长,
|----hashSet :底层数据结构是哈希表。线程是非同步的
add(index,element) :在指定的索引位插入元素。
3,获取:
Object get(index) :通过索引获取指定元素。
int indexOf(obj) :获取指定元素第一次出现的索引位,如果该元素不存在返回-1;所以,通过-1,可以判断一个元素是否存在。
List subList(start,end) :获取子列表。
4,修改:
Object set(index,element) :对指定索引位进行元素的修改。
5,获取所有元素:
ListIterator listIterator():list集合特有的迭代器。
如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator,该接口只能通过List集合的listIterator方法获取。
int nextIndex():返回对next的后续调用所d返回元素的索引。
previous():返回列表中的前一个元素。
int previousIndex():返回对previous的后续调用返回元素的索引。
void remove():从列表中移除由next或previous返回的最后一个元素(可选操作)。
void set(E e):用指定元素替换next或previous返回的最后一个元素(可选操作)。
List集合支持对元素的增、删、改、查。
导致的原因是:集合引用和迭代器引用在同时操作元素,通过集合获取到对应的迭代器后,在迭代中,进行集合引用的元素添加,迭代器并不知道,所以会出现异常情况。
答:是通过元素的两个方法,hashCode和equals完成,如果元素的hashcode值相同,才会判断equals是否为true。如果元素的hashcode值不同,不会调用equals
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法。
TreeSet:可以对set集合中的元素进行排序。Set集合的功能和collection是一致的。
list特有方法,凡是可以操作角标的方法都是该体系特有的方法
- import java.util.*;
- public class listDemo {
- public static void method()
- {
- ArrayList a1=new ArrayList();
- //添加元素
- a1.add("java01");
- a1.add("java02");
- sop("原集合是:"+a1);
- //在指定位置添加元素,相当于插入,
- a1.add(1, "java09");
- //删除指定位置元素。按角标删除
- a1.remove(2);
- //修改元素。按角标修改
- a1.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());
- }
- //通过indexof获取对象的位置
- sop("index="+a1.indexOf("java02"));
- List sub=a1.subList(1, 3);
- sop("sub="+sub);
- }
- public static void main(String[] args) {
- //演示列表迭代器
- ArrayList a1=new ArrayList();
- //添加元素
- a1.add("java01");
- a1.add("java02");
- sop("原集合是:"+a1);
- ListIterator li=a1.listIterator();
- 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("hasNext"+li.hasNext());//正向遍历
- sop("hasPrevious():"+li.hasPrevious());//逆向遍历。
- sop(a1);
- /** //在迭代过程中,准备添加或删除元素
- Iterator it=a1.iterator();//这个迭代器不能添加
- while(it.hasNext())
- {
- Object obj=it.next();
- if(obj.equals("java02"))
- // a1.add("java003");
- it.remove();//将Java02的引用从集合中删除了。
- sop("obj="+obj);
- }
- */
- }
- public static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
LinkedList
addLast();
在jdk1.6以后。
offerFirst();相当于add
offerLast();
getFirst():获取链表中的第一个元素。如果链表为空,抛出NoSuchElementException;
getLast();获取元素但不删除元素如果集合中没有元素,会出现NosuchElementException
在jdk1.6以后。
peekFirst();获取链表中的第一个元素。如果链表为空,返回null。
peekLast();相当于get
removeFirst():获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,抛出NoSuchElementException
removeLast();获取元素并删除元素,如果集合中没有元素,会出现NosuchElementException
在jdk1.6以后。
pollFirst();//相当于remove
获取链表中的第一个元素,但是会删除链表中的第一个元素。如果链表为空,返回null。
pollLast();获取元素并删除元素,如果集合中没有元素,会返回null
- import java.util.*;
- public class LinkedListDemo {
- public static void main(String[] args) {
- LinkedList link=new LinkedList();
- link.addFirst("java01");
- link.addFirst("java011");
- link.addFirst("java01111");//头插法
- link.addFirst("java02");
- link.addLast("java0121");//尾插法
- link.addLast("java011211");
- sop(link);
- sop(link.getFirst());//获取头
- sop(link.getLast());//获取尾
- sop("size="+link.size());//获取长度。
- sop(link.removeFirst());
- while(!link.isEmpty())
- {
- sop(link.removeFirst());//正着取出
- sop(link.removeLast());//反着取出
- }
- }
- public static void sop(Object obj)
- {
- System.out.print(obj);
- }
- }
练习范例:
- import java.util.*;
- public class ArrayListTest {
- public static void main(String[] args) {
- ArrayList al=new ArrayList();
- al.add("java01");
- al.add("java02");
- al.add("java03");
- al.add("java04");
- al.add("java01");
- al.add("java02");
- /**
- * 在迭代时循环中next只能调用一次,就要hasNext判断一次。
- Iterator it=al.iterator();
- while(it.hasNext())
- {
- sop(it.next()+"....."+it.next());
- }
- */
- sop(al);
- al=singleElement(al);
- sop(al);
- }
- public static ArrayList singleElement(ArrayList al)
- { //定义一个临时容器
- ArrayList newal=new ArrayList();
- Iterator it=al.iterator();
- while(it.hasNext())
- {
- Object obj=it.next();
- if(!newal.contains(obj))
- {
- newal.add(obj);
- }
- }
- return newal;
- }
- public static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
Set接口
HashSet集合保证元素唯一性:通过元素的hashCode方法,和equals方法完成的。
当元素的hashCode值相同时,才继续判断元素的equals是否为true。
如果为true,那么视为相同元素,不存。如果为false,那么存储。
如果hashCode值不同,那么不判断equals,从而提高对象比较的速度。
|--LinkedHashSet:有序,hashset的子类。
|--TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。
对于HashSet集合,判断元素是否存在,或者删除元素,底层依据的是hashCode方法和equals方法。
用于对Set集合进行元素的指定顺序排序,排序需要依据元素自身具备的比较性。
如果元素不具备比较性,在运行时会发生ClassCastException异常。
所以需要元素实现Comparable接口,强制让元素具备比较性,复写compareTo方法。
依据compareTo方法的返回值,确定元素在TreeSet数据结构中的位置。
TreeSet方法保证元素唯一性的方式:就是参考比较方法的结果是否为0,如果return 0,视为两个对象重复,不存。
1:让元素自身具备比较性,需要元素对象实现Comparable接口,覆盖compareTo方法。
2:让集合自身具备比较性,需要定义一个实现了Comparator接口的比较器,并覆盖compare方法,并将该类对象作为实际参数传递给TreeSet集合的构造函数。
- import java.util.*;
- public class HashSetTest {
- public static void main(String[] args) {
- HashSet hs=new HashSet();
- hs.add(new Person1("a1",11));
- hs.add(new Person1("a2",12));
- hs.add(new Person1("a3",13));
- hs.add(new Person1("a2",12));
- hs.add(new Person1("a3",13));
- hs.add(new Person1("a4",14));
- //判断是否存在
- //hs.contains(new Person1("a1",11));//先判断的是hash值。
- //hs.remove(new Person1("a2”,13));//
- Iterator it=hs.iterator();
- while(it.hasNext())
- {
- Person1 p=(Person1)it.next();
- sop(p.getAge()+"::"+p.getName());
- }
- }
- public static void sop(Object obj)
- {
- System.out.println(obj);
- }
- }
- class Person1
- { private String name;
- private int age;
- Person1(String name,int age)
- {
- this.name=name;
- this.age=age;
- }
- public int hashCode()
- {
- //return 60;
- return name.hashCode()+age*39;
- }
- public boolean equals(Object obj)
- {
- if(!(obj instanceof Person1))
- return false;
- Person1 p=(Person1)obj;
- System.out.println(this.name+",,,,,,,,,,,,,,"+p.name);
- return this.name.equals(p.name)&&this.age==p.age;
- }
- public String getName()
- {
- return name;
- }
- public int getAge()
- {
- return age;
- }
- }
Set 接口:
|---HashSet :数据结构是哈希表,线程是非同步的
保证元素唯一性的原理:判断元素的hashCode值是否相同
如果相同,还会继续判断元素的equals方法,是否为true
|---TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树
保证元素唯一性的依据
compareTo方法return 0;
TreeSet排序的第一种方式,让元素自身具备比较性,
元素需要实现Comparable接口,覆盖compareTo方法。
这种方式也称为元素的自然顺序,或叫默认顺序。
TreeSet排序的第二种方式,当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。
comparable接口强行对实现它的每个类的对象进行整体排序。
记住,排序时,当主要条件相同时,一定要判断一下次要条件 。
可以对set集合中的元素进行排序,底层数据结构是二叉树,保证元素唯一性的依据
compareTo方法return 0;
TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现comparable接口,覆盖compareTo方法, 这种方式也称为元素的自然顺序,或叫默认顺序。
- import java.util.Iterator;
- import java.util.TreeSet;
- public class TreeSetDemo {
- public static void main(String[] args) {
- TreeSet ts=new TreeSet();
- ts.add(new Student("lisi09",33));
- ts.add(new Student("lisi02",34));
- ts.add(new Student("lisi23",23));
- ts.add(new Student("lisi01",23));
- ts.add(new Student("lisi23",23));
- ts.add(new Student("lisi01",3));
- Iterator it=ts.iterator();
- while(it.hasNext())
- { Student stu=(Student)it.next();
- System.out.println(stu.getName()+"...."+stu.getAge());
- }
- }
- }
- 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;
- }
- public int compareTo(Object obj)
- { return 1;//输入的字符串的比较正向,变-1反向
- /**if(!(obj instanceof Student))
- throw new RuntimeException("不是学生对象");
- Student s=(Student)obj;
- System.out.println(this.name+"ddddd"+s.name);
- if(this.age>s.age)
- return 1;
- if(this.age==s.age)
- {
- return this.name.compareTo(s.name);
- }
- return -1;
- */
- }
- }
提示:字符串本身具备比较性,但是它的比较方式不是所需要的,这时就只能使用比较器。
- import java.util.*;
- public class TreesetTest {
- public static void main(String[] args) {
- TreeSet ts=new TreeSet(new stringlencomparator()); //传入比较器
- ts.add("aa");
- ts.add("cess");
- ts.add("agweg");
- ts.add("s");
- Iterator it=ts.iterator();
- while(it.hasNext())
- {
- System.out.println(it.next());
- }
- }
- }
- class stringlencomparator implements Comparator
- {
- public int compare(Object o1,Object o2) //比较器
- {
- String s1=(String)o1;
- String s2=(String)o2;
- /** if(s1.length()>s2.length())
- return 1;
- if(s1.length()==s2.length())
- return 0;
- return -1;
- */
- int num=new Integer(s1.length()).compareTo(new Integer(s2.length())); //排序
- if(num==0)
- return s1.compareTo(s2);
- return num;
- }
- }