------- android培训、java培训、期待与您交流! ----------集合类
面向对象语言对事物的体现都是以对象的形式,所以为了方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式.在很多情况下,我们不知道在程序中需要创建多少个对象,这时就不能依靠定义引用对象的变量来持有每一个对象。存储对象的容器就能帮我们解决这样的问题,而集合便是这样的容器。
数组和集合类同是容器,有何不同
- 数组:存储对象,但长度是固定的,存储基本数据类型。
- 集合:存储对象,但长度是可变,存储对象。
集合的特点:
- 集合只用于存储对象,集合长度是可变的,集合可以存储不同类型的对象。
- 集合中存贮的是对象的地址。
集合框架概述
- Java中集合类定义主要是在java.util.*包下面。
- 集合的框架体系:
![](https://img-my.csdn.net/uploads/201303/25/1364178486_5820.JPG)
为什么需要这么多容器?
- 因为每一个容器对数据的存贮方式都有不同,这种存贮方式称为:数据结构
- Collection: 根接口(共性方法)(List:Set:)
- 增:add()方法的参数是Object,以便于接收任意类型的对象
- boolean add(E e):向容器中添加对象
- addAll(Collcetion<? extends E> c):将指定 collection 中的所有元素都添加到此 collection 中
- 删
- void clear():移除此 collection 中的所有元素
- boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话返回true
- boolean removeAll(Collcetion<?> c)将集合中相同的部分去掉。
- 判断
- boolean contains(Object o):判断是否包含某一个对象
boolean containsAll(Collcetion<?> c):如果此 collection 包含指定 collection 中的所有元素,则返回true。
boolean equals(Object o):比较此 collection 与指定对象是否相等。
boolean isEmpty():判断容器中是否有对象。
- 查
- 迭代器:取出集合内部元素的一个接口,该接口的子类定义在集合的内部。这样就可以直接访问集合内部的元素。因为每一个容器的数据结构不同,所以取出动作的实现细节也不同,但是都有共性内容(判断和取出)。因此将其共性抽取。以后任何集合只要在内部实现Iterator接口,就可以将其元素取出。
- iterater iterater()
- 代码示例:
import java.util.*; class CollectionDemo { public static void main(String[] args) { ArrayList a1 = new ArrayList(); ArrayList a2 = new ArrayList(); //添加元素(对象) 运用 add(Object obj) a1.add("Where"); a1.add("there"); a1.add("is"); a2.add("I"); a2.add("Love"); a2.add("You"); a1.addAll(a2); //获取个数,集合的长度 sop("a1的Size:"+a1.size()+"\n"); //删除元素 sop(a1.remove("You")+"\n"); //返回值为布尔型 sop(a1+"\n"); //取交集 sop(a2.retainAll(a1));//返回的结果是布尔型,表示是否有交集 sop("a1和a2的交集是:"+a2+"\n");//a1里现在是a1与a2的交集 //取出元素 //通过Iterator取出集合内的元素。 for (Iterator it=a1.iterator();it.hasNext() ; ) { sop(it.next()+"\t"); } } public static void sop(Object o) { System.out.print(o); } }
List:(Collection的子类之一)- 特点:元素是有序的,元素可以重复,因为该集合体系中有索引
- 常见子类对象:
- ArrrayList:底层的数据结构使用的是数组结构
- 特点:查询速度很快,因为有索引(角标),但增删速度稍慢。是线程不同步的。
- LinkedList:底层使用的是链表的结构
- 特点:增删速度很快,但查询速度稍慢,因为每一个元素都链接到前一元素
- Vector:底层是数组结构,线程同步,被ArrayList代替。
- ArrrayList:底层的数据结构使用的是数组结构
- List中的特有方法:(凡事可以操作角标的方法都是该体系的特有方法)
- 增
- void add(index,E e):在指定位置添加对象
- void add(index,Collection);在指定位置插入一个集合
- 删
- E remove(index):删除指定位置上的元素
- 改:
- set(index,element):修改指定位置上的元素
- 查:
- E get(index):获取指定位置的元素。
- 通过迭代器Iterator进行取出:取出所有的元素。
- 迭代器是取出元素的方式。把取出方式定义在集合的内部,这样取出方式就可以直接访问集合的内的元素。
- 因为每一个容器的数据结构有所不同,所以取出的动作也不一样。但是都有共性的内容,判断和取出。因此就把这些共性的方法抽取出来,形成Iterator接口。
- int indexOf(Object o):获取该对象在容器中的位置。
- List subList(int fromIndex, int toIndex)获取指定到指定结束位置的对象。
- 列表迭代器:ListIterator是Iterator的子接口
- 在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常,所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取
- 在迭代时,不可以通过集合对象的方法操作集合中的元素。因为会发生ConcurrentModificationException异常,所以在迭代时,只能用迭代器的方法操作元素,可是Iterator方法是有限的。只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,ListIterator。该接口只能通过List集合的listIterator方法获取
- 增
- LinkedList:(链接列表)
- 特有方法:
- void addFirst(E e)
- void addLast(E e)
- E get First()//get方法获取元素,但是不删除元素。当集合为空时,则抛出没有这个元素的异常。
- E getLast()
- E remove()//remove方法获取元素,并且删除该元素。当集合为空时,则抛出没有这个元素的异常
- E remove(int index)
- E removeFirst()
- E removeLast()
- 在JDK1.6中出现了替代方法
- offerFirst() 替代void add方法
- offerLast()
- peekFirst()替代get方法
- peekList()
- pollFirst()替代remove方法
- pollLast()
- LinkedList示例:
/* 使用LinkedList模拟一个堆栈或者队列数据结构。 堆栈:先进后出 如同一个杯子。 队列:先进先出 First in First out FIFO 如同一个水管。 */ import java.util.*; class DuiLie { private LinkedList link; DuiLie() { link = new LinkedList(); } public void myAdd(Object obj) { link.addFirst(obj); } public Object myGet() { return link.removeFirst(); } public boolean isNull() { return link.isEmpty(); } } class LinkedListTest { public static void main(String[] args) { DuiLie dl = new DuiLie(); dl.myAdd("java01"); dl.myAdd("java02"); dl.myAdd("java03"); dl.myAdd("java04"); while(!dl.isNull()) { System.out.println(dl.myGet()); } } }
- 特有方法:
- Vector方法中的特殊方法(枚举)
- Enumeration elements()就是vector特有的取值方式(枚举)。相当与迭代器。
- Enumeration elements()中的方法:
- boolean hasMoreElements()
- E nextElements()
- Enumeration elements()中的方法:
- 由于枚举的名称以及方法的名称都过长,所以被迭代器取代了.
- Enumeration elements()就是vector特有的取值方式(枚举)。相当与迭代器。
Set- 特点:没有索引,元素不可重复,存入和取出的顺序不一定一致。
- 功能:和ArrayList
- 常见子类:
- hashSet():底层数据结构是哈希表。
- TreeSet():底层的数据结构是二叉树。可以对Set集合中的元素进行排序(默认按ASCII编码)。
- hashSet()
- hashSet如何保证元素的唯一性?
- 通过调用元素的hashCode()方法和equals()方法来完成。如果元素的hashCode值相同,就接着判断equals()方法。如果都相同,则不会把重复的元素存进集合。(只有在hashCode的值相同的时候才会调用equasl方法进行比较。)
- 在尽力hashSet集合时,一般都要复写hashCode()和equals()方法,建立自己特有的比较方式,来提高工作效率。并且在复写hashCode()方法时,得保证hash值的唯一性。
- 对于判断元素是否存在以及删除等操作,依赖的方法是元素的hashCode()和equals()方法。
- hashSet如何保证元素的唯一性?
- TreeSet()
- 可以对Set集合中的元素进行排序(默认是按字母的ASCII码的顺序)。
- 原理:当每次存进一个元素的时候,该集合对象就会自动调用该元素的compareTo()方法,将这个元素与已有的元素进行比较。通过返回的值将元素通过二叉树的结构进行存放。
- TreeSet的排序:
- TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法。也种方式也成为元素的自然顺序,或者叫做默认顺序。
- 示例:
class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add(new Student("lisi02",22)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi09",19)); ts.add(new Student("lisi08",19)); 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 int compareTo(Object obj)//覆盖compareTo方法,建立自己的比较方式。 { 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; } public String getName() { return name; } public int getAge() { return age; } }
- 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 int compareTo(Object obj) { if(!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); Student s = (Student)obj; if(this.age>s.age) return 1; if(this.age==s.age) { return this.name.compareTo(s.name); } return -1; } public String getName() { return name; } public int getAge() { return age; } } class TreeSetDemo2 { public static void main(String[] args) { TreeSet ts = new TreeSet(); 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)); Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } } } class MyCompare implements Comparator //定义比较器 实现Compare接口 { public int compare(Object o1,Object o2) { Student s1 = (Student)o1; Student s2 = (Student)o2; int num = s1.getName().compareTo(s2.getName()); if(num==0) { return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge())); } return num; } }
- TreeSet排序的另外一种方式:在构造集合的时候向集合中传入一个“比较器实体”。
- 应用场合:当元素自身不具备比较性时,或者具备的比较性不是所需要的。
- 比较器的定义:定义一个类实现Comparator接口,覆盖其中的compare()方法。compare()方法中定义的是比较的内容。
- 当集合中的元素和集合都有比较的功能的时候,输出的结果是按照集合的比较方式排序的。
- 示例:
import java.util.*; //导入包 class Student implements Comparable //定义学生类,并且让其具有比较性 { private int age; private String name; private String id; Student(String name,int age,String id) { this.name = name; this.age = age; this.id = id; } public int compareTo(Object obj) { if (!(obj instanceof Student)) throw new RuntimeException("不是学生对象"); else { System.out.println(this.getName()+" "+this.getAge()); Student s = (Student) obj; if(this.age != s.age) return this.age - s.age; else if(this.name != s.name) return this.name.compareTo(s.name); return this.id.compareTo(s.id); } } public String getName() { return(this.name); } public int getAge() { return(this.age); } public String getId() { return(this.id); } } class MyCompartor implements Comparator //定义一个比较器 { public int compare(Object obj1,Object obj2) { if (!(obj1 instanceof Student)&&(obj2 instanceof Student)) throw new RuntimeException(obj1+"and"+obj2+"中有对象不是学生类"); else { Student stu1 = (Student) obj1; Student stu2 = (Student) obj2; int num1 = new Integer(stu1.getName().length()).compareTo(new Integer(stu2.getName().length())); if (num1 == 0) { int num2 = new Integer(stu1.getAge()).compareTo(new Integer(stu2.getAge())); if(num2 == 0) { return new String(stu1.getId()).compareTo(new String(stu2.getId())); } return num2; } return num1; } } } class MyTreeSet { public static void main(String[] args) { TreeSet ts = new TreeSet(new MyCompartor()); ts.add(new Student("Zhang,Honemi",23,"520")); ts.add(new Student("Zhang,Honemi",22,"520")); ts.add(new Student("Zhang,Honemi",25,"520")); ts.add(new Student("Zhang,Honemi",23,"521")); ts.add(new Student("Zhang,Honemix",23,"520")); for (Iterator it = ts.iterator();it.hasNext() ; ) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"……"+stu.getAge()+"……"+stu.getId()); } } }
Map接口极其子类
Map接口(Map(Key,Value))是实现键-值映射数据结构的一个框架,可以用于存储通过键-值引用的对象。映射与集合有明显的区别,映射中的每个对象都是成对存在的。映射中存贮的每个对象都是通过一个键(key)对象来获取值(value)对象,键值的作用相当于数组中的索引,每一个键值都是唯一的(一个值只能对应一个键),可以利用键值来存贮数据结构中指定位置上的数据。这种存取不由键对象本身决定,而是通过一种散列技术进行处理,从而产生一个被称做散列码的整数值。散列码通常是一个偏置量,它相当于分派给映射的存贮去的起始位置。理想情况下,通过散列技术得到的散列码应该是在给定范围内均匀分布的整数值,并且每个键对象都应该得到不同的散列码。
- Map接口中定义的常用方法
- 添加
- V put(K key,Value v):向指定集合中添加指定的键-值映射关系。返回该键值之前对应的Value值。
- void putAll(Map<? extends K,? extends V> m ):从指定映射中将所有映射关系复制到此映射中
- 删除
- void clear():移除集合中的所有的映射关系。
- V remove(Object key):如果存在指定的键对象,则移除该键对象的映射关系,并返回与该键对应的Value的值。
- 判断
- boolean containsKey(Object key):如果存在指定的键的映射关系,则返回true,否则返回false
- boolean containsValue(Object Value):如果存在指定值的映射关系,则返回true,否则返回false
- boolean equals(Object o)用来查看指定的对象与该对象是否为同一个对象,是同一个对象返回true,否则返回false
- boolean isEmpty():判断该集合是否存在键-值映射。如果不存在,返回true
- 获取
- V get(Object key):如果存在指定的键对象,则返回与该键对象对应的值对象,否则返回null
- int hashCode():返回此映射的哈希码值
- int size():获得该集合中键-值映射关系的个数。
- Collection<V> values():返回此映射中包含的值的Collection视图。
- entrySet()
- keySet()
- 常见方法演示:
import java.util.*; class MyMap { public static void main(String[] args) { Map<String,String> mymap = new HashMap<String,String>();//定义一个Map集合 //向集合中添加元素 /* 1.通过put方法存元素的时候,返回值是该键之前对应的值 2.在HashMap中null可以当作键值或者Value值存在。 */ sop(mymap.put("01","Zhanghongmei")); sop(mymap.put("01","Zhanghongmei1")); mymap.put("02","ZHM"); mymap.put("03","meimei"); mymap.put("04",null); mymap.put(null,"MM"); //判断集合中是否存在指定键或者指定值 sop("mymap是否存在键值03:"+mymap.containsKey("03")); sop("mymap是否存在值ZHM:"+mymap.containsValue("ZHM")); sop("mymapz中是否存在键值003:"+mymap.containsKey("003")); sop("mymap中是否存在值ZHMx:"+mymap.containsValue("ZHMx")); //通过values方法,把集合中value值,取出。并存储在一个Collection集合中,返回该集合。 sop("mymap中所有的值是:"+mymap.values()); } public static<E> void sop(E e) { System.out.println(e); } } /* 运行结果 =================================== null Zhanghongmei mymap是否存在键值03:true mymap是否存在值ZHM:true mymapz中是否存在键值003:false mymap中是否存在值ZHMx:false mymap中所有的值是:[MM, null, Zhanghongmei1, ZHM, meimei] =================================== */
- Map集合的两种取出方式:
- keySet():
- 思想:将Map集合中所有的键存入Set集合,再通过Set集合的迭代器,取出所有的键值,最后通过get(Object key)方法取出所有的Value值。
- 代码示例:
import java.util.*; class MyMap1 { public static void main(String[] args) { Map<String,String> mymap = new HashMap<String,String>(); //存入元素 mymap.put("01","Zhang"); mymap.put("02","Hong"); mymap.put("03","Mei"); //通过keySet方法取出键值 Set<String> se = mymap.keySet(); //获取Set集合的迭代器 for(Iterator<String> it = se.iterator();it.hasNext();) { String key = it.next(); //通过Map集合的get方法取出对应的value的值 String value = mymap.get(key); sop(key+"="+value); } } public static<E> void sop(E e) { System.out.println(e); } } /* 运行结果 ============================== 01=Zhang 02=Hong 03=Mei ============================== */
- Set<Map.Entry<k,v>> entrySet():
- Map.Entry是一个接口里面有5个方法。
- boolean equals(Object o) :比较指定对象与此项的相等性。
- K getKey() :返回与此项对应的键。
- V getValue() :返回与此项对应的值
- int hashCode() :返回此映射项的哈希码值
- V setValue(V value) :用指定的值替换与此项对应的值。
- boolean equals(Object o) :比较指定对象与此项的相等性。
- 思想:将集合的通过调用entrySet()方法,将该集合内的所有元素的映射关系取出,并存进一个Set集合中,并返回这个集合。通过迭代器依次取出这种关系Map.Entry,然后调用Map.Entry里面的方法可以取出key值和value值,还可以替换value值。
- 代码示例:
import java.util.*; class MyMap2 { public static void main(String[] args) { //建立一个Map集合 Map<String,String> mymap = new HashMap<String,String>(); //向Map集合中添加元素 mymap.put("02","-zhangsan2"); mymap.put("03","-zhangsan3"); mymap.put("01","-zhangsan1"); mymap.put("04","-zhangsan4"); //将Map集合中的关系通过entrySet方法取出,存放在Set集合中 Set<Map.Entry<String,String>> se = mymap.entrySet(); //通过迭代器一次取出这种关系 for (Iterator<Map.Entry<String,String>> it = se.iterator();it.hasNext() ; ) { Map.Entry<String,String> re = it.next(); //通过Map.Entry的方法取出key和value值 String key = re.getKey(); String value = re.getValue(); sop(key+"="+value); } } public static<E> void sop(E e) { System.out.println(e); } } /* 运行结果 ================================== 04=-zhangsan4 01=-zhangsan1 02=-zhangsan2 03=-zhangsan3 ================================== */
- Map.Entry是一个接口里面有5个方法。
- keySet():
- 添加
- Map接口的实现子类
- Hashtable
- 特点:
- 此类实现一个哈希表,底层是哈希表数据接口该哈希表将键映射到相应的值。任何非
null
对象都可以用作键或值。 - 为了成功地在哈希表中存储和获取对象,用作键的对象必须实现
hashCode
方法和equals
方法。 - 出现在1.0版本,线程是同步的。
- 此类实现一个哈希表,底层是哈希表数据接口该哈希表将键映射到相应的值。任何非
- 特点:
- HashMap
- 特点:
- 底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。除了非同步和允许使用 null 之外,HashMap 类与Hashtable 大致相同。
- 底层是哈希表数据结构,允许使用 null 值和 null 键,该集合是不同步的。将hashtable替代,jdk1.2.效率高。除了非同步和允许使用 null 之外,HashMap 类与Hashtable 大致相同。
- 特点:
- TreeMap
- 特点:
- 底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
- 和Set很像,Set底层就是使用了Map集合。
- 底层是二叉树数据结构。线程不同步。可以用于给map集合中的键进行排序。
- 特点:
- Hashtable
- 增:add()方法的参数是Object,以便于接收任意类型的对象