一、Java集合类
1.概念
我们都知道Java数组的长度是固定的,在同一个数组中只能存放相同类型的数据。数组既可以存放基本数据类型,也可以存放引用数据类型。但是数组最大的缺陷是长度固定,数组一旦被创建,长度就不能改变。
Java集合引入的目的是:为了使程序能方便地存储和操纵数目不固定的一组数据,JDK类库提供了Java集合。
2.特点
所有的Java集合类都位于java.util包中。和数组不同,Java集合中不能存放基本数据类型,只能存放对象的引用。对于基本数据类型,Java会自动装箱为其对应的包装类。
3.分类
(1)Set(集):集合中的对象不按特定方式排列,并且没有重复的对象。它的有些实现类可以对集合中的对象按特定方式排序。
(2)Link(链表):集合中的对象按照索引位置排序,可以有重复的元素。索引从0开始。
(3)Queue(队列):集合中的元素按照先进先出的规则来排列,在队头删除元素,队尾插入元素。允许有重复的元素。
(4)Map(映射):集合中的每个元素包括一对键(Key)对象和值(Value)对象。集合中没有重复的键对象,允许有重复的值对象。
其中,Set、Link、Queue都是Connection接口的子接口;Map接口没有继承Connection接口。
4.Collection和Iterator接口
4.1 Collection接口
下面是一些Collection接口的通用方法。
(1)boolean add(Object o) 向集合中加入一个对象的引用。
(2)void clear() 删除集合中的所有元素,即不再持有对这些对象的引用。
(3)boolean contains(Object o) 判断在集合中是否持有对该对象的引用。
(4)Iterator iterator() 返回一个Iterator对象,可以用它来遍历集合中的元素。
(5)boolean isEmpty() 判断集合是否为空
(6)boolean remove(Object o) 从集合中删除对一个对象的引用。
(7)int size() 返回集合中元素的数目
(8)Object[] toArray() 返回一个对象数组,该数组包含集合中的所有对象。
4.2 Iterator接口
下面是一些Iterator接口的通用方法。
(1)hasNext():判断集合中是否遍历完毕,如果没有,就返回true.
(2)next():返回下一个元素。
(3)remove():从集合中删除由next()返回的当前元素。
5.集合的输出
集合共有三种输出方式,分别是foreach、Iterator(迭代器)和LinkIterator(双向迭代器)。Iterator方式只能从前向后打印,而LinkIterator方式可以双向打印,但要注意,从后往前打印时一定要先从前向后打印。
public static void main(String[] args) {
Collection<String> list = new ArrayList<>();
list.add("hello");
list.add("hello");
list.add("bit");
//方式一 迭代器
Iterator iterator1 = list.iterator();
while (iterator1.hasNext()) {
System.out.print(iterator1.next()+" ");//hello hello bit
}
//方式二 双向迭代器 ListIterator 可以由后向前输出。要进行由后向前输出时,一定要先进行从前向后输出,否则无法实现双向。
ListIterator<String> listIterator = ((ArrayList<String>) list).listIterator();
System.out.println("由前向后输出为:");
while(listIterator.hasNext()){
System.out.print(listIterator.next()+" ");
}
System.out.println("\n由后向前输出为:");
while (listIterator.hasPrevious()) {
System.out.print(listIterator.previous()+" ");
}
//结果:由前向后输出为:
//hello hello bit
//由后向前输出为:
//bit hello hello
System.out.println();
//方式三 foreach
for(String mylist:list){
System.out.print(mylist+" ");//hello hello bit
}
}
二、List集合接口
1.List接口较Collection接口扩充的方法是:
public E get(int index) 根据索引取得数据。
public E set(int index,E element) 修改数据。
2.特点
元素以线式方式存储,允许有重复数据。
3.子接口
3.1 ArrayList接口
ArrayList代表长度可变的数组,允许对元素的随机访问,但是向ArrayList中插入和删除数据的速度较慢。ArrayList类还实现了RandomAccess接口,该接口没有任何方法,仅仅是个标识类型的接口。凡是实现RandomAccess接口的类意味着具有良好的快速随机访问性能。
3.2 LinkedList接口
实现采用链表数据结构。向LinkedList插入和删除数据的元素较快,但是随机访问的速度较慢。LinkedList单独具有addFirst()、addLast()、getFirst()、getLast()、removeFirst()、removeLast()等方法,这些方法使得LinkedList可以作为堆栈、队列和双向队列使用。
3.3 Vector接口(旧的子类)
使用较少,用法和ArrayList类似。Enumeration输出接口只支持Vector接口,而不支持Collection、Set、List等接口。
Enumeration接口的方法有:
public boolean hasMoreElements(); 判断是否有下一个元素
public E nextElements(); 取得元素
public Enumeration elements() 取得Enumeration对象
代码实现:
public static void main(String[] args) {
Vector<String> vector=new Vector<>();
vector.add("hello");
vector.add("xiaomi");
vector.add("xiaohong");
Enumeration<String> enumeration=vector.elements();
while(enumeration.hasMoreElements()){
System.out.print(enumeration.nextElement()+" ");
}
}
结果:hello xiaomi xiaohong
3.4 ArrayList、Vector和LinkedList接口的区别?
它们三个都是Link接口的子类。
先比较ArrayList和Vector
(1)使用时间不同:ArrayList是从JDK1.2提供的,而Vector是从JDK1.0就提供了。
(2)处理形式不同:ArrayList是异步处理,线程不安全;Vector是同步处理,线程安全。
(3)数据安全:ArrayList线程不安全;Vector线程安全。
(4)输出形式:ArrayList支持Iterator、ListIterator、foreach;而Vector支持Iterator、ListIterator、foreach、Enumeration。
再比较ArrayList和LinkedList
(1)对数据的操作:ArrayList随机访问的速度块,但是插入和删除的速度慢。
而LinkedList插入和删除数据的速度快,但是随机访问的速度慢。
(2)封装的内容不同:ArrayList封装的是数组,而LinkedList封装的是链表。
(3)时间复杂度:ArrayList的时间复杂度是1,而LinkedList的复杂度是n。
4.打印方式
因为Link类中有get()方法,可以直接得到元素。
//List类型的打印
public static void code1(){
List<String> list=new ArrayList<String>();
list.add("hello");
list.add("hello");
list.add("hello");
//List类型时有四种输出形式
//方式一 Collection接口不再适用,因为get()是List子接口提供的。
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
//方式二
for(String alist:list){
System.out.println(alist);
}
//方式三 迭代器
Iterator iterator1=list.iterator();
while(iterator1.hasNext()){
System.out.println(iterator1.next());
}
//方式四
System.out.println(list);
}
结果:方式一、二和三输出相同,共输出三行,每行都是hello。
而方式四输出的是:[hello,hello,hello]。
5.其它方法
5.1 排序
List只能对集合中的对象按索引位置排序,如果希望对List中的对象按照其它特定方式进行排序,可以借助Collections类和Comparator接口。
如:
List<Integer> list=new ArrayList<Integer>();
list.add(1);
list.add(90);
list.add(2);
Collections.sort(list);
System.out.println(list);//[1,2,90]
5.2删除元素
集合操作Java简单类时,对于remove()和contains()都需要equals()的支持。因此,如果在程序中覆写了equals(),要注意考虑。
List<Person> personList=new ArrayList<Person>();
personList.add(new Person("张三",10));
personList.add(new Person("李四",11));
personList.add(new Person("王五",12));
System.out.println(personList);
System.out.println(personList.remove(new Person("张三",10)));//false,因为这个对象是新new了一个,和原来链表上的不是同一个对象。
System.out.println(personList);
三、Set集合
1.Set接口并没有对Collection接口进行扩充。因此在Set接口中没有get()。
2.特点:
元素不允许重复。
3.子类
3.1 HashSet
HashSet类按照哈希算法来存取集合中的对象。HashSet还有子类LinkedHashSet类,它不仅实现了哈希算法,而且实现了链表数据结构,因此提高了插入和删除数据的性能。
3.2 TreeSet
3.2.1 TreeSet类实现了SortedSet接口,具有排序功能(升序)。
public static void main(String[] args) {
Set<String> set=new TreeSet<String>();
set.add("hello");
set.add("hello");
set.add("bit");
//输出方式一
System.out.println(set+"元素共有:"+set.size()+"个");//[bit, hello]元素共有:2个
//方式二
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.print(iterator.next()+" ");//bit hello
}
System.out.println();
//方式三
for(String s:set){
System.out.print(s+" ");//bit hello
}
}
//如果使用HashSet,则会输出[hello,bit]
3.2.2 TreeSet的排序分析
TreeSet支持两种排序方式:自然排序和客户化排序,默认情况下使用自然排序(升序)。排序实际上是针对对象数组进行的排序处理,而如果要进行对象数组的排序,对象所在的类一定要是实现Comparale接口并且覆写compareTo(),即客户化排序。
如
package com.xunpu.collection;
import javax.swing.text.html.HTMLDocument;
import java.util.*;
class Person{
private String name;
private int age;
public Person(String name,int age) {
this.name = name;
this.age=age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class PersonComparator implements Comparator<Person>{
@Override//实现逆序
public int compare(Person o1, Person o2) {
if(o1.getName().compareTo(o2.getName())>0){
return -1;
}
if(o1.getName().compareTo(o2.getName())<0){
return 1;
}
return 0;
}
}
public class TestCollection {
public static void main(String[] args) {
//创建TreeSet对象时,在构造方法中指定采用PersonComparator来比较Person对象。
Set<Person> personSet=new TreeSet<Person>(new PersonComparator());
personSet.add(new Person("张三",10));
personSet.add(new Person("李四",11));
personSet.add(new Person("王五",12));
for(Person p:personSet){
System.out.println(p.getName()+" "+p.getAge());
}
}
}
结果输出:
王五 12
李四 11
张三 10
4.重复元素的判断
TreeSet接口重复元素的判断依靠的是Comparable接口完成的。而HashSet子类,跟Comparable子类没有任何关系,所以它判断重复元素依靠的是Object类中的两个方法:
hash码:public native int hashCode();
对象比较:public boolean equals(Object object);
Java中进行对象的比较有两步,首先通过对象的唯一编码找到对象的信息,当编码匹配后,再调用equals()进行内容的比较。
注意:如果要想标识对象的唯一性,一定需要equals()和hashCode()共同调用。
对象判断必须两个方法equals()、hashCode()返回值都相同时,才能判断相同。