集合框架(List和Set)
来源:互联网 发布:app php服务器搭建 编辑:程序博客网 时间:2024/05/20 12:51
一、概述
集合是一种可变数据项的容器,具有统一的父类接口Collection<E>
(Map
并没有继承之),与其子集合的关系如下 图,集合的特点是长度可变,可以存储多种类型的对象(不加泛型时)。这也是与数组的两点最大的不同。
Collection
最为根接口,List
、Set
、Queue
接口均直接继承自它,Map
接口虽然不是直接继承自Collection
,但是接口中使用到了Collection
,即Map的数据也是使用Collection
存储的。
研究集合必不可少的是先研究Collection
接口的内容,先从接口名字定义开始说起public interface Collection<E> extends Iterable<E>
,这是集合的根接口,<E>
是JDK1.5开始的泛型,其功能是提高安全性,增强针对性,具体介绍后面再说。Iterable<E>
接口是迭代器,下面有具体介绍。Collection
接口提供了一些集合的共性方法,如:
boolean add(E e)
添加一条数据。boolean addAll(Collection<? extends E> c)
添加另一个集合内的元素。void clear()
清除所有数据。boolean contains(Object o)
是否包含指定数据。Iterator<E> iterator()
返回迭代器。boolean remove(Object o)
删除指定数据。<T>T[] toArray(T[] a)
返回数据的数组形式等等。boolean retainAll(Collection<?> c)
取与集合c的交集。boolean removeAll(Collection<?> c)
取与集合c的差集。
二、迭代器
一种集合的取出方式,用于集合的数据的遍历等。不同容器的数据结构不同,所以取出的动作实现不同,具体的取出动作定义在每个容器的内部,这样取出方式就可以直接访问集合内部元素,取出方式就被定义成了内部类。但是都有共性内容判断和取出,共性抽取便形成了Iterator
接口(迭代器)。
迭代器的使用示例(暂时不考虑泛型):
ArrayList alist = new ArrayList();alist.add("java01");alist.add("java02");alist.add("java03");alist.add("java04");for(Iterator it = alist.iterator(); it.hasNext(); ) { System.out.println(it.next());}
三、List
List
为Collection的常见子接口之一,元素有序,可以重复,有索引。 List
有些特有的方法,和下标相关的一些方法,如:
- 增:add(index, element)
指定位置添加元素,addAll(index, Collection)
指定位置添加一个集合的元素。
- 删:remove(index)
删除指定为的元素。
- 改:set(index, element)
修改指定位置的元素。
- 查:get(index)
获取指定位置的元素,subList(from, to)
获取[from, to)
段的子List
,listIterator()
获取List
特有的迭代器,indexOf(E)
获取对象的位置。
ListIterator
ListIterator
是Iterator
的子接口,在迭代时不可以通过集合的操作对集合进行操作,会发生并发修改异常,但是Iterator
的操作是有限的,如果想对元素进行添加和修改等,就需要用到其子接口ListIterator
,该接口只能通过List
的listIterator()
方法获取,示例代码如下:
ArrayList alist = new ArrayList();alist.add("java01");alist.add("java02");alist.add("java03");alist.add("java04");for(ListIterator it = alist.listIterator(); it.hasNext(); ) { System.out.println(it.next()); it.add("java");}System.out.println(alist);//输出结果是java01java02java03java04[java01, java, java02, java, java03, java, java04, java]
通过上面可以看到,ListIterator
在获取之后其遍历的内容就已经确定下来了。 ListIterator
还有逆向遍历功能。
ArrayList alist = new ArrayList();alist.add("java01");alist.add("java02");alist.add("java03");alist.add("java04");ListIterator it = alist.listIterator();while(it.hasNext()) { System.out.println(it.next());}while(it.hasPrevious()) { System.out.println(it.previous());}// 输出的结果是java01java02java03java04java04java03java02java01
List
中具体对象特点
List
有三个具体的子类,分别是ArrayList
、LinkedList
和Vector
。三者的特点与不同如下:
ArrayList
:底层数据结构为数组结构,线程非同步,查询速度快,增删速度慢,效率比Vector
高,最早出现在JDK1.2版本。初始长度默认为10,空间不足时50%延长。LinkedList
:底层数据结构为链表结构,线程非同步,查询速度慢,增删速度快,最早出现在JDK1.2版本。Vector
:底层数据结构是数组结构,线程同步,与ArrayList
有相同的功能,已被ArrayList
代替,最早出现在JDK1.0版本。默认长度为10,空间不足时100%延长。
Vector
的特点
Vector
的特有的一点就是,Vector
的枚举(Vector
的特有取出方式),和迭代器类似,名为Enumeration
,ArrayList
中没有此功能,但是由于方法名过长,且没有移除功能,已被Iterator
代替,所以一般优先考虑使用Iterator
,示例代码如下:
Vector v = new Vector();v.add("java01");v.add("java02");v.add("java03");Enumeration en = v.elements();while(en.hasMoreElements()) { System.out.println(en.nextElement());}// 输出结果为java01java02java03
LinkedList
LinkedList
的特有方法:addFirst(E e)
、addLast(E e)
添加到头部或者尾部、getFirst()
、getLast()
获取头部元素或者尾部元素、removeFirst()
、removeLast()
删除头部元素或者尾部元素,并返回删除的元素,没有会报NoSuchElementException
,这些是LinkedList
所特有的方法。JDK1.6版本名称发生了变化,分别变成了offerFirst(E e)
,offerLast(E e)
,peekFirst()
,peekLast()
,pollFirst()
,pollLast()
,没有会返回null
。 LinkedList
练习,模拟队列进行添加和取出动作。示例代码如下:
import java.util.*;class MyQueue { private LinkedList link; MyQueue() { 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) { MyQueue q = new MyQueue(); q.myAdd("java01"); q.myAdd("java02"); q.myAdd("java03"); q.myAdd("java04"); while(!q.isNull()) { System.out.println(q.myGet()); } }}
ArrayList
ArrayList
练习,去除ArrayList
中的重复项。代码示例如下:
import java.util.*;class ArrayListTest { public static void main(String[] args) { ArrayList list = new ArrayList(); list.add("java01"); list.add("java02"); list.add("java01"); list.add("java02"); list.add("java01"); list.add("java03"); // 去除重复前 System.out.println(list); list = singleElement(list); // 去除重复后 System.out.println(list); } public static ArrayList singleElement(ArrayList list) { //定义一个临时容器。 ArrayList newList = new ArrayList(); // 获取迭代器 Iterator it = list.iterator(); while(it.hasNext()) { Object obj = it.next(); if(!newList.contains(obj)) { newList.add(obj); } } return newList; }}
ArrayList
练习,自定义类添加至ArrayList
,需要覆盖自定义类的equals
方法。
import java.util.*;class Person { private String name; private int age; Person(String name, int age) { this.name = name; this.age = age; } // 覆盖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; } public String toString() { return "Name:" + this.name + " Age:" + this.age; }}class ArrayListTest { public static void main(String[] args) { ArrayList list= new ArrayList(); list.add(new Person("lisi01",30)); list.add(new Person("lisi02",32)); list.add(new Person("lisi02",32)); list.add(new Person("lisi04",35)); list.add(new Person("lisi03",33)); list.add(new Person("lisi04",35)); System.out.println(list); list = singleElement(list); System.out.println(list); } public static ArrayList singleElement(ArrayList al) { // 定义一个临时容器。 ArrayList newList = new ArrayList(); // 取出迭代器 Iterator it = al.iterator(); while(it.hasNext()) { Object obj = it.next(); if(!newList.contains(obj)) newList.add(obj); } return newList; }}
四、Set
元素无序(存入与取出的顺序不一致),元素不可重复。有两个主要子类:HashSet
和TreeSet
。
HashSet
:底层数据结构为哈希表。TreeSet
:底层数据结构为二叉树。
HashSet
根据hashCode()
和equals()
方法进行存储。add
时,如果是第一次添加返回true
(添加成功),否则返回false
(添加失败)。示例代码如下:
import java.util.*;class HashSetDemo { public static void main(String[] args) { HashSet hs = new HashSet(); // 第一次添加java01返回true System.out.println(hs.add("java01")); // 第二次添加java01返回false System.out.println(hs.add("java01")); hs.add("java02"); hs.add("java03"); hs.add("java03"); hs.add("java04"); // 遍历集合 Iterator it = hs.iterator(); while(it.hasNext()) { System.out.println(it.next()); } }}
HashSet
存储自定义对象,自定义对象需要覆盖hashCode
和equals
方法,当hashCode
值相同、equals
返回真时,认为是同一个对象。添加时,当hashCode
值不同时,不会调用equals
比较,当hashCode
的值相同时,才会调用equals
方法比较两个对象。示例代码如下:
import java.util.*;/** *姓名和年龄相同认为是同一个人 */class Person { private String name; private int age; Person(String name,int age) { this.name = name; this.age = age; } public int hashCode() { System.out.println(this.name+"....hashCode"); return name.hashCode() + age*37; } public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p = (Person)obj; System.out.println(this.name+"...equals.."+p.name); 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 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.add(new Person("a4",14)); // 遍历集合中的人 Iterator it = hs.iterator(); while(it.hasNext()) { Person p = (Person)it.next(); System.out.println(p.getName()+"::"+p.getAge()); } }}// 运行结果为a1....hashCodea2....hashCodea3....hashCodea2....hashCodea2...equals..a2a4....hashCodea3::13a1::11a4::14a2::12
从上面代码运行的结果可以看出,当添加new Person("a2",12)
时,因为集合中已经有这个人了,所以hashCode
的返回值已经存在,因此便会调用equals方法判断,最终结果还是此人已存在,所以最总集合中只有4个人。
HashSet的判断和删除依据,可以看到判读元素是否存在和删除元素都是首先根据hashCode
值,然后再通过equals
判断是否相同。
import java.util.*;/** *姓名和年龄相同认为是同一个人 */class Person { private String name; private int age; Person(String name,int age) { this.name = name; this.age = age; } /** *统一返回1作为哈希值 */ public int hashCode() { System.out.println("hashCode"); return 1; } /** * 姓名和年龄相同认为是同一个人 */ public boolean equals(Object obj) { if(!(obj instanceof Person)) return false; Person p = (Person)obj; System.out.println(this.name+"...equals.."+p.name); 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 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.add(new Person("a4",14)); System.out.println("--------"); // 判断是否存在元素 hs.contains(new Person("a4", 14)); System.out.println("--------"); // 删除指定元素 hs.remove(new Person("a1", 11)); }}// 运行结果为hashCodehashCodea2...equals..a1hashCodea3...equals..a1a3...equals..a2hashCodea2...equals..a1a2...equals..a2hashCodea4...equals..a1a4...equals..a2a4...equals..a3--------hashCodea4...equals..a1a4...equals..a2a4...equals..a3a4...equals..a4--------hashCodea1...equals..a1
TreeSet
可以对集合中的元素进行排序。底层数据结构为二叉树,中序遍历便是TreeSet
的顺序。示例代码如下:
import java.util.*;class TreeSetDemo { public static void main(String[] args) { TreeSet ts = new TreeSet(); ts.add("asdas"); ts.add("abc"); ts.add("beds"); ts.add("abd"); Iterator it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next()); } }}// 运行结果为abcabdasdasbeds
对于自定义对象的排序,一般有两种做法,一是自定义对象自己实现Comparable
接口,二是集合提供比较器(Comparator
接口)。
自定义对象实现Comparable
接口,示例代码如下:
import java.util.*;class Student implements Comparable { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } /** *比较结果又三种,负数表示小于,0表示等于,正数表示大于 */ public int compareTo(Object obj) { 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) { // String类已经实现了Comparable接口 return this.name.compareTo(s.name); } return -1; } public String getName() { return name; } public int getAge() { return age; }}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)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi01",40)); // 遍历集合 Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } }}
集合提供比较器(Comparator
接口)的比较方式,用于元素不具备比较性或者具备的比较性不是用户所需要的时。示例代码如下:
import java.util.*;class Student implements Comparable { private String name; private int age; Student(String name,int age) { this.name = name; this.age = age; } /** *比较结果又三种,负数表示小于,0表示等于,正数表示大于 */ public int compareTo(Object obj) { 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; }}class TreeSetDemo2 { public static void main(String[] args) { TreeSet ts = new TreeSet(new MyCompare()); 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)); ts.add(new Student("lisi007",20)); ts.add(new Student("lisi01",40)); Iterator it = ts.iterator(); while(it.hasNext()) { Student stu = (Student)it.next(); System.out.println(stu.getName()+"..."+stu.getAge()); } }}class MyCompare implements Comparator { 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; }}
五、泛型
泛型的出现解决了类型不同的安全问题,JDK1.5版本开始出现的。具体做法就是在集合定义时指明数据类型,如ArrayList<String> list= new ArrayList<String>()
,这样一来如果向list
中添加非String
类型对象时,就会在编译时期提示ClassCastException
异常。示例代码如下:
import java.util.*;class GenericDemo { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("abc01"); list.add("abc0991"); list.add("abc014"); // Iterator也有对应的泛型 Iterator<String> it = al.iterator(); while(it.hasNext()) { System.out.println(s+":"+s.length()); } }}
自定义类中使用泛型的概念。试用于用数据类型不确定时,示例代码如下:
class Worker {}class Student {}/** *泛型类,使用与引用数据类型不确定时。 */class Utils<Q> { private Q q; public void setObject(Q q) { this.q = q; } public Q getObject() { return q; }}class GenericDemo3 { public static void main(String[] args) { Utils<Worker> u = new Utils<Worker>(); u.setObject(new Worker()); Worker w = u.getObject();; }}
泛型定义在方法上,示例代码如下:
class Demo { public <T> void show(T t) { System.out.println("show:"+t); } public <Q> void print(Q q) { System.out.println("print:"+q); } /** * 静态方法不可以访问类上的泛型,可使用静态泛型方法,注意:泛型标识<E>需放在返回值前。 */ public static <E> void printf(E e) { System.out.println("printf:"+e); }}class GenericDemo4 { public static void main(String[] args) { Demo demo = new Demo(); demo.show("Hi"); demo.print("Hello"); Demo.printf(5); }}//执行结果为show:Hiprint:Helloshow:5
泛型限定
一般有三种情况,
<?>
:?为通配符。<? extends E>
:E和E的子类,称为上限。<? super E>
:E和E的父类,称为下限。
如对所有类型的ArrayList
进行遍历输出,示例代码如下:
public static void print(ArrayList<?> list) { Iterator<?> it = list.iterator(); while(it.hasNext()) { System.out.println(it.next().toString()); }}
对Person
或者Person
的子类Student
进行遍历并输出,示例代码如下:
public static void print(ArrayList<? extends Person> list) { Iterator<? extends Person> it = list.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); }}
对于<? super E>
并不常用,举一个TreeSet里的例子,TreeSet(Comparator<? super E> comparator)
,使用父类的比较器进行子类的比较。示例代码如下:
import java.util.*;class Person { private String name; Person(String name) { this.name = name; } public String getName() { return name; } public String toString() { return "Person :"+name; }}class Student extends Person { Student(String name) { super(name); }}class Worker extends Person { Worker(String name) { super(name); }}/** * 定义使用与Person的比较器 */class Comp implements Comparator<Person> { public int compare(Person p1,Person p2) { // 倒序 return p2.getName().compareTo(p1.getName()); }}class GenericDemo { public static void main(String[] args) { // 使用使用父类的比较器进行比较 TreeSet<Student> ts = new TreeSet<Student>(new Comp()); ts.add(new Student("abc03")); ts.add(new Student("abc02")); ts.add(new Student("abc06")); ts.add(new Student("abc01")); Iterator<Student> it = ts.iterator(); while(it.hasNext()) { System.out.println(it.next().getName()); } // 使用使用父类的比较器进行比较 TreeSet<Worker> ts1 = new TreeSet<Worker>(new Comp()); ts1.add(new Worker("wabc--03")); ts1.add(new Worker("wabc--02")); ts1.add(new Worker("wabc--06")); ts1.add(new Worker("wabc--01")); Iterator<Worker> it1 = ts1.iterator(); while(it1.hasNext()) { System.out.println(it1.next().getName()); } }}// 执行结果为abc06abc03abc02abc01wabc--06wabc--03wabc--02wabc--01
- 集合框架(List和Set)
- 集合框架List和Set
- Java集合框架 List和Set
- 集合框架--List和Set的特点
- 集合框架List\Set
- 黑马程序员___13java基础 集合框架 LIST和SET集合
- 集合框架(List 、Set)
- 集合框架之一 List-Set
- java集合框架---List/Set
- 集合框架-List与Set
- 集合框架 map,set,list
- java集合框架-List和Set和相关的方法
- Set集合和List集合
- 常用对象API(集合框架-List和Set的特点)
- Java集合框架Collection(List、Set和Map)
- 黑马程序员java学习—集合框架List和Set
- 集合框架中的list、set和map的浅析
- 黑马程序员--集合框架:List、Set和Map体系
- linux TC
- 黑马程序员_反射学习小结
- Windows编程--线程的切换
- command命令模式(行为模式)之我见
- DC setup 注意事项
- 集合框架(List和Set)
- [转]Matlab.Net混编
- SQLite 使用主键,ROWID 及自增列
- 利用CSS预处理技术实现项目换肤功能(less css + asp.net mvc4.0 bundle)
- java8提供的简单函数式接口
- The connection to adb is down, and a severe error has occured. You must restart adb and Eclipse.
- IOS中的协议-代理,传值
- 怎样与领导谈加薪以及谈加薪的技巧
- 几种开源虚拟产品的介绍及性能比较