16 集合
16.2 集合类
为何出现集合类:
为方便对多个对象的操作,就对对象进行存储,集合就是存储对象最常用的一种方式。
集合类与数组的区别:
- 数组的长度是固定的,集合可以动态扩展;
数组只能通过数组下标访问元素,类型固定,而有的集合可以通过任意类型查找所映射的具体对象;
import java.util.ArrayList; public class CollectionDemo { public static void main(String[] args) { ArrayList a = new ArrayList(); a.add("java1"); a.add("java2"); a.add("java3"); a.add("java4"); ArrayList b = new ArrayList(); b.add("java1"); b.add("java2"); b.add("java6"); b.add("java9"); a.retainAll(b); write("a:"+a); write("b:"+b); base_method(); } public static void base_method(){ //创建一个集合容器,使用Collection接口的子类ArrayList ArrayList a1 = new ArrayList(); //添加元素 a1.add("java1"); a1.add("java2"); a1.add("java3"); a1.add("java4"); write(a1); //删除元素 a1.remove("java2"); write(a1); write("java4是否存在:"+a1.contains("java4")); write("集合是否为空:"+a1.isEmpty()); } public static void write(Object obj){ System.out.println(obj); } }
运行结果:
集合的作用:
a、在类的内部,对数据进行组织;
b、简单而快速的搜索大数量的条目;
c、有的集合接口,提供了一系列排列有序的元素,并且可以在序列中间快速的插入或者删除有关元素;
d、有的集合接口,提供了映射关系,可以通过关键字(key)去快速查找到对应的唯一对象,而这个关键字可以是任意的。
Java集合框架:Collection、Map
16.2.1 Collection接口
Collection类
- List:元素是有序的,元素可以重复,因为该集合体系有索引;
- Set:元素是无序,元素不可以重复。
a)是List、Set和Queue接口的父接口
b)定义了可用于操作List、Set和Queue的方法–增删改查
16.2.1.1 ArrayList
List:特有的常见方法。
有一个共性特点就是都可以操作角标。
List接口及其实现类—ArrayList
a)List是元素有序并且可以重复的集合,被称为序列;
b)List可以精确的控制每个元素的插入位置,或删除某个位置元素;
c)ArrayList——数组序列,是List的一个重要实现类;
d)ArrayList底层是由数组实现的。
特点:查询速度快,但是增删稍慢。
List接口及其实现类—LinkedList
特点:增删速度很快,查询速度稍慢.
List接口及其实现类—Vector
底层是数组数据接口/线程同步,被ArrayList替代了.
例1:
import java.util.ArrayList;
import java.util.Iterator;
public class ListDemo {
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add("java1");
a1.add("java2");
a1.add("java3");
Iterator it = a1.iterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("java2"))
a1.add("java4");//不能通过集合对象方法操作元素
write("obj="+obj);
}
write("a1="+a1);
}
public static void write(Object obj){
System.out.println(obj);
}
}
运行结果:
List集合特有的迭代器,ListIterator是Interator的子接口。
在迭代时,不可通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常,如上例;所以,在迭代器中,只能用迭代器方法操作元素,但是Interator方法时有限的,只能对元素进行判断(hasNext()),删除(remove())和取出(next())操作,如果需要进行其他操作,则需要使用其子接口ListIterator。该接口只能通过List集合的ListInterator获取。如例2、例3。
例2:
import java.util.ArrayList;
import java.util.ListIterator;
public class ListDemo {
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add("java1");
a1.add("java2");
a1.add("java3");
ListIterator it = a1.listIterator();
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("java2"))
it.add("java4");
write("obj="+obj);
}
write("a1="+a1);
}
public static void write(Object obj){
System.out.println(obj);
}
}
例3:
import java.util.ArrayList;
import java.util.ListIterator;
public class ListDemo {
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add("java1");
a1.add("java2");
a1.add("java3");
ListIterator it = a1.listIterator();
write("hasPrevous="+it.hasPrevious());
while(it.hasNext()){
Object obj = it.next();
if(obj.equals("java2")){
//it.add("java4");
it.set("javab");
}
}
write("hasPrevous="+it.hasPrevious());
write("hasNext="+it.hasNext());
while(it.hasPrevious()){
it.previous();
}
write("a1="+a1);
}
public static void write(Object obj){
System.out.println(obj);
}
}
例4
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest {
public static void main(String[] args) {
ArrayList a1 = new ArrayList();
a1.add(new Person("zhangsan",31));
a1.add(new Person("lisi",32));
a1.add(new Person("wangwu",33));
a1.add(new Person("zhaoliu",34));
a1.add(new Person("wangwu",33));
/* Iterator it = a1.iterator();
while(it.hasNext()){
Person p = (Person)it.next();
write(p.getName()+":"+p.getAge());
}*/
a1 = singleElement(a1);
Iterator it1 = a1.iterator();
while(it1.hasNext()){
Person p1 = (Person)it1.next();
write(p1.getName()+":"+p1.getAge());
}
}
public static ArrayList singleElement(ArrayList a1){
ArrayList newA1 = new ArrayList();
Iterator it = a1.iterator();
while(it.hasNext()){
Object obj=it.next();
if(!newA1.contains(obj))
newA1.add(obj);
}
return newA1;
}
public static void write(Object obj){
System.out.println(obj);
}
}
class Person{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
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;
}
}
运行结果:
16.2.1.2 Vector
枚举是Vector特有的取出方式,枚举和迭代是一样的。
因为枚举的名称以及方法的名称都过长,所以被迭代器取代了.
例5
import java.util.Enumeration;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
Vector v = new Vector();
v.add("java1");
v.add("java2");
v.add("java3");
Enumeration en = v.elements();
while(en.hasMoreElements()){
System.out.print(en.nextElement());
}
}
}
运行结果:java1java2java3
16.2.1.3 LinkedList
LinkedList方法:
addFirst();
addLast();
16.2.1.4 HashSet
Set:元素不可以重复,是无序。
Set接口中的方法和Collection一致。
|–HashSet:内部数据结构是哈希表,是不同步的。
|–TreeSet:可以对Set集合中的元素进行排序,是不同步的。
哈希表确定元素是否相同
- 判断的是两个元素的哈希值是否相同。
如果相同,再判断两个对象的内容是否相同。 - 判断哈希值相同,其实判断的是对象的HashCode方法。判断内容相同,用的是equals方法。
- 如果哈希值不同,不需要判断equals。
例6:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet hs = new HashSet();
hs.add(new Person("a1",13));
hs.add(new Person("a1",13));
hs.add(new Person("a2",14));
hs.add(new Person("a3",11));
write(hs.contains(new Person("a2",14)));
hs.remove(new Person("a1",13));
Iterator it = hs.iterator();
while(it.hasNext()){
Person p= (Person)it.next();
write(p.getName()+":"+p.getAge());
}
}
public static void write(Object obj){
System.out.println(obj);
}
}
class Person{
private String name;
private int age;
Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
public int hashCode(){
System.out.println(this.name+"..hashcode");
return name.hashCode()+age;
}
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
System.out.println(this.name+"..equals"+this.age);
return this.name.equals(p.name) && this.age == p.age;
}
}
运行结果:
Ps:
- 一般使用HashSet会重写HashCode和equals。
- 对于判断元素是否存在(contains),以及删除(remove)等操作,依赖的方法是元素的hashCode和equals方法。
16.2.1.5 TreeSet
可以对Set集合中的元素进行排序。
例7:
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
ts.add(new Student("Lili",13));
ts.add(new Student("Lily",19));
ts.add(new Student("Mick",15));
ts.add(new Student("Black",15));
ts.add(new Student("Black",11));
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;
public String getName() {
return name;
}
public int getAge() {
return 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;
System.out.println(this.name+"..equals.."+this.age);
if(this.age>s.age)
return 1;
else if(this.age<s.age)
return -1;
else
return (this.name.compareTo(s.name));
}
}
运行j结果:
排序时,当主要条件相同时,必须判断次要条件。
TreeSet底层数据时二叉树,保证元素唯一性的语句,应用compareTo方法return 0;
TreeSet对元素进行排序的方式一:
让元素自身具备比较功能,元素就需要实现Comparable接口,覆盖compareTo方法。如例7.TreeSet对元素进行排序的方式二:
让元素自身不具备比较功能,或者具备的比较性不是所需要的,这时让集合自身初始化时具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。如例8。方式二更具有实用性。
例8:
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompre());
ts.add(new Student1("Lili",13));
ts.add(new Student1("Lily",19));
ts.add(new Student1("Mick",15));
ts.add(new Student1("Black",15));
ts.add(new Student1("Black",11));
Iterator it = ts.iterator();
while(it.hasNext()){
Student1 stu = (Student1)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}
}
class MyCompre implements Comparator{
public int compare(Object o1, Object o2) {
Student1 s1 = (Student1)o1;
Student1 s2 = (Student1)o2;
int num = s1.getName().compareTo(s2.getName());
if(num==0)
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
return num;
}
}
class Student1 {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
Student1(String name,int age){
this.name = name;
this.age = age;
}
public int compareTo(Object obj){
if(!(obj instanceof Student1))
throw new RuntimeException("不是学生对象");
Student1 s = (Student1)obj;
System.out.println(this.name+"..equals.."+this.age);
if(this.age>s.age)
return 1;
else if(this.age<s.age)
return -1;
else
return (this.name.compareTo(s.name));
}
}
运行结果: