集合(Ⅰ) ---------- Collection
2015-10-20 10:49
288 查看
一、集合
一个集合是代表一组对象的一个对象,集合中的这一组对象称为它的元素。集合主要来处理各种类型的对象的聚集。集合保留了对 Object 类的引用,因此,任何数据类型的对象都可以存放在集合中。集合中包含3个重要接口: Collection、Set、List,它们都可以用来组织多个对象,但是又各不相同。
Collection 集中的对象存放没有顺序,而且允许重复。
Set 对象的无序聚集,但不允许重复。
List 有序的对象聚集,对象按照一定顺序存放,同时允许重复。
集合的继承关系如图:
二、Collection 接口
Collection 接口是单值存放的最大父接口,可以向其中保存多个单值(单个对象)数据。此接口定义如下方法:boolean add(E e) // 向集合中插入元素 boolean addAll(Collection<? extends E> c) // 将一个集合的内容插入进来 void clear() // 清除此集合中所有的元素 boolean contains(Object o) // 判断某一个对象是否在集合中存在 boolean containsAll(Collection<?> c) // 判断一组对象是否在集合中存在 boolean equals(Object o) // 对象比较 int hashCode() // 哈希码 boolean isEmpty() // 集合是否为空 Iterator<E> iterator() // 为 Iterator 接口实例化 boolean remove(Object o) // 删除指定元素 boolean removeAll(Collection<?> c) // 删除一组对象 boolean retainAll(Collection<?> c) // 保存指定内容 int size() // 求出集合的大小 Object[] toArray() // 讲一个集合变成对象数据 <T> T[] toArray(T[] a) // 指定好返回的对象数组类型
2.1 Collection 子接口
如果直接操作使用 Collection 接口,则表示操作意义不明确,所以在 Java 开发中不提倡使用直接操作 Collection 接口,主要子接口如下:- List 可以存放重复的内容。
- Set 不能存放重复的内容,重复的内容靠 hashCode() 和 equals()两个方法区分。
- Queue 队列接口。
- SortedSet 可以对集合中的数据进行操作。
三、List 接口
与 Collection 接口不同的是,在 List 接口中大量地扩充了 Collection 接口,下面列出 List 中对象Collection 接口的扩展方法:void add(int index, E element) // 在指定位置增加元素 boolean addAll(int index, Collection<? extends E> c) // 在指定位置增加一组元素 E get(int index) // 返回列表中指定位置的元素。 int indexOf(Object o) // 返回此列表中第一次出现的指定元素的索引 int lastIndexOf(Object o) // 返回此列表中最后出现的指定元素的索引 ListIterator<E> listIterator() // 为 ListIterator 接口实例化 E remove(int index) // 移除列表中指定位置的元素 List<E> subList(int fromIndex, int toIndex) // 取出集合的子集合 E set(int index, E element) // 用指定元素替换列表中指定位置的元素
void add(int index, E element) // 在指定位置增加元素 boolean addAll(int index, Collection<? extends E> c) // 在指定位置增加一组元素 E get(int index) // 返回列表中指定位置的元素。 int indexOf(Object o) // 返回此列表中第一次出现的指定元素的索引 int lastIndexOf(Object o) // 返回此列表中最后出现的指定元素的索引 ListIterator<E> listIterator() // 为 ListIterator 接口实例化 E remove(int index) // 移除列表中指定位置的元素 List<E> subList(int fromIndex, int toIndex) // 取出集合的子集合 E set(int index, E element) // 用指定元素替换列表中指定位置的元素
3.1 List 接口的常用子类
3.1.1 ArrayList
ArrayList 是 List 子类,可以直接通过对象的多态性为 List 接口实例化。public class ArrayListDemo01 { public static void main(String[] args) { List<String> allList = null; // 定义 List 对象 Collection<String> allCollection = null; // 定义 Collection 对象 allList = new ArrayList<String>(); allCollection = new ArrayList<String>(); // 向集合中添加元素 allList.add("hello"); allList.add(0, "world"); // List 扩展 Collection 的 add()方法 System.out.println(allList); allCollection.add("HELLO"); allCollection.add("WORLD"); allList.addAll(allCollection); System.out.println(allList); // 删除元素 allList.remove(0); // List 扩展 Collection 的remove() 方法 allList.remove("HELLO"); System.out.println(allList); // 遍历元素 for (int i = 0; i < allList.size(); i++) { System.out.println(allList.get(i)); } // 将集合变成对象数组 String[] strings = allList.toArray(new String[]{}); // allList.toArray() for (int i = 0; i < strings.length; i++) { System.out.println(strings[i]); } } }
3.1.2 Vector
从整个 Java 的集合发展历史来看,Vector算是一个元老级的类,在JDK1.0时就已经存在此类。到了JDK1.2之后重点强调集合框架的概念,所以定义很多新接口(如List等),但是考虑一大部分用户已经习惯了使用 Vector 类,所以 Java 的设计者就让 Vector 类多实现了一个 List 接口,这才将其保留下来。由于其是 List 子类,所以 Vector 类的使用与之前的并没有太大的区别。public class VectorDemo01 { public static void main(String[] args) { List<String> allList = null; allList = new Vector<String>(); // 直接使用的是 List 接口進行操作 allList.add("hello"); allList.add(0, "world"); for (int i = 0; i < allList.size(); i++) { System.out.print(allList.get(i) + " "); } System.out.println(); System.out.println("---------------------"); // 使用 Vector 類中的 addElement(E o) 方法,是最早的向集合中增加元素的操作 Vector<String> vectors = new Vector<String>(); vectors.addElement("pegasus"); vectors.addElement("flyingdancing"); Enumeration<String> enums = vectors.elements(); while (enums.hasMoreElements()) { String value = enums.nextElement(); System.out.println(value); } } }
3.1.3 ArrayList 与 Vector 的区别
ArrayList 在 JDK1.2 之后推出的,属于新的操作类。采用异步处理方式,性能更高,属于非线程安全的操作类,只能使用 Iterator、foreach输出。Vector 在 JDK1.0 时推出,属于旧的操作类。采用同步处理方式,性能较低,属于线程安全的操作类,可以使用 Iterator、foreach、Enumeration 输出。
3.1.4 LinkedList 子类与 Queue 接口
LinkedList 表示的是一个链表的操作类,此类实现了 List 接口,同时实现了 Queue 接口。Queue 表示的是队列操作接口,采用 FIFO(先进先出)的方式操作。Queue 接口定义的方法
public E element() // 找到链表的标表头 public boolean offer(E o) // 将指定元素增加到链表的结尾 public E peek() // 找到但并不删除链表的头 public E poll() // 找到并删除此链表的头 public E remove() // 检索并移除表头
LinkedList 类的主要方法
public void addFirst(E o) // 在链表开头增加元素 public void addLast(E o) // 在链表结尾增加元素 public boolean offer(E o) // 将指定元素增加到链表的结尾 public E removeFirst() // 删除链表的第一个元素 public E removeLast() // 删除链表的最后一个元素
示例操作
public class LinkedListDemo01 { public static void main(String[] args) { LinkedList<String> linkedLists = new LinkedList<String>(); linkedLists.add("A"); linkedLists.add("B"); linkedLists.add("C"); System.out.println("初始化鏈表:" + linkedLists); linkedLists.addFirst("X"); linkedLists.addLast("Y"); System.out.println("增加頭和尾之後的鏈表:" + linkedLists); System.out.println("1-1、element() 方法找到表頭:" + linkedLists.element()); System.out.println("2-1、peek()方法找到表頭:" + linkedLists.peek()); System.out.println("2-2、找到之後的鏈表內容:" + linkedLists); System.out.println("3-1、poll()方法找到表頭:" + linkedLists.poll()); System.out.println("3-2、找到之後的鏈表內容:" + linkedLists); System.out.println("以FIFO的方式輸出:"); for (int i = 0; i < linkedLists.size(); i++) { System.out.print(linkedLists.get(i) + "、"); } } }
四、Set
Set 接口也是 Collection 接口的子接口,但与Collection 或 List 接口不同的是,Set 接口中不能加入重复的元素。Set 接口的实例无法像 List 接口那样可以进行双向输出,因为此接口没有提供像 List 接口的 get(int index) 方法。4. 1 Set 接口的常用子类
4.1.1 HashSet
HashSet 线程不安全,存取速度快。可以通过元素的两个方法, hashCode 和 equals 来完成保证元素唯一性。如果元素的 hashCode 值相同,才会判断 equals 是否为 true 。如果元素的 hashCode 值不同,不会调用 equals。示例:
public class HashSetDemo01 { public static void main(String[] args) { HashSet<Person> hs = new HashSet<Person>(); hs.add(new Person("pegasus", 21)); hs.add(new Person("mbyd", 16)); hs.add(new Person("flyingdancing", 35)); hs.add(new Person("wbjbaqblca", 10)); hs.add(new Person("wbjbaqblca", 10)); Iterator<Person> iterators = hs.iterator(); while (iterators.hasNext()) { Person person = iterators.next(); System.out.println(person.getName() + ", " + person.getAge()); } } } class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
4.1.2 TreeSet
特点a)、底层的数据结构为二叉树结构(红黑树结构)
b)、可对Set集合中的元素进行排序,是因为:TreeSet类实现了Comparable接口,该接口强制让增加到集合中的对象进行了比较,需要复写compareTo方法,才能让对象按指定需求进行排序,并加入集合。
注意:排序时,当主要条件相同时,按次要条件排序。
c)、保证数据的唯一性的依据:通过compareTo方法的返回值,是正整数、负整数或零,则两个对象较大、较小或相同。相等时则不会存入。
Tree排序的两种方式
a)、第一种排序方式:自然排序
让元素自身具备比较性。元素需要实现Comparable接口,覆盖compareTo方法。这种方式也被称为元素的自然顺序,或者叫做默认顺序。
b)、第二种方式:比较器
当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。定义一个比较器,将比较器对象作为参数传递给TreeSet集合的构造函数。
比较器构造方式:定义一个类,实现Comparator接口,覆盖compare方法。
当两种排序都存在时,以比较器为主。
示例:
public class TreeSetDemo01 { public static void main(String[] args) { TreeSet<Person> hs = new TreeSet<Person>(new LenCompare()); hs.add(new Person("pegasus", 21)); hs.add(new Person("mbyd", 16)); hs.add(new Person("flyingdancing", 35)); hs.add(new Person("wbjbaqblca", 10)); hs.add(new Person("wbjbaqblca", 10)); Iterator<Person> iterators = hs.iterator(); while (iterators.hasNext()) { Person person = iterators.next(); System.out.println(person.getName() + ", " + person.getAge()); } } } class Person implements Comparable<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Person other = (Person) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } @Override public int compareTo(Person o) { Person person = o; if (this.age == person.age) { return this.name.compareTo(person.name); } return this.age - person.age; } } // 定义一个比较器,以姓名长度为主要比较 class LenCompare implements Comparator<Person> { public int compare(Person o1, Person o2) { int num = new Integer(o1.getName().length()).compareTo(new Integer(o2.getName().length())); if (num == 0) { return new Integer(o1.getAge()).compareTo(o2.getAge()); } return num; } }
4.1.3 HashSet 与 TreeSet 区别
1、TreeSet 是二差树实现的,Treeset中的数据是自动排好序的,不允许放入null值 。2、HashSet 是哈希表实现的,HashSet中的数据是无序的,可以放入null,但只能放入一个null,两者中的值都不能重复,就如数据库中唯一约束 。
3、HashSet要求放入的对象必须实现HashCode()方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。
相关文章推荐
- 没时间与时间管理
- C++中指针和引用的异同
- iOS避免文件被同步到iCloud或iTunes
- HTTP网络协议必知必会大盘点
- StringUtils中的isBlank与isEmpty
- 对数据进行处理
- mysql分表的三种方法
- torch7 reinstall error missing ncurses dependence
- Xcode使用教程详细讲解(上)
- 【error C2660: “GetDlgItem”: 函数不接受 1 个参数】
- 爬塔系统的分析
- Android控件:WebVIew(三)日历选择器
- 工作记录 2015-10-20
- centos下设置ssh连接时间
- web前端开发浏览器兼容性 - 持续更新
- MAC在Finder栏显示所浏览文件夹路径的方法
- LA 5010 Go Deeper 2-SAT 二分
- 添加TextView隐藏进度条的方法
- Xcode7中你一定要知道的炸裂调试神技
- NSDateFormatter的yyyy和YYYY到底什么区别