您的位置:首页 > 其它

集合(Ⅰ) ---------- 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是一样,所以放入的内容不能重复。但是同一个类的对象可以放入不同的实例。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: