14,集合框架
14.1集合的由来
对于同一种类型的数据,我们可以用数组存储,数组多了,还可以用二维数组存;不同类型的数据可以使用StringBuffer、StringBuilder;那么如果对象多了,就可以用集合存储。
java中,存在不同的集合容器,对这些集合进行向上抽取,就形成了集合框架。
集合的特点:
1,集合是存储对象的容器。
2,集合的长度是可变的。
3,集合不能存储基本数据类型值。
14.2集合框架结构图
Collection<E>是单列集合的根接口,Collection<E>常用两大体系:List,Set
List接口常用子类:Vector<E>,ArrayList<E>,LinkedList<E>.
Set接口常用子类:HashSet<E>,TreeSet<E>,LinkedHashSet<E>.
Map<K,V>是双列集合的根接口,存储的都是键值对,存在着键值对的映射关系,Map<K,V>常用子类有:TreeMap<K,V>,HashMap<K,V>,Hashtable<K,V>及其子类Properties集合(是一个可以结合IO流使用的集合).
14.3 Collection接口及Iterator迭代器原理
Collection接口是单列集合的根接口,内部封装了对所有单列集合操作的共性方法,不同的集合对集合中元素的内部操作方式不尽相同,Collection集合的子类通过复写和定义子类的特有内容,实现对不同集合的操作。
Iterator迭代器:Java中每个集合容器的内部数据结构不同,集合元素的取出方式也不同,对这些集合元素的取出方式进行不断的向上抽取,抽取为一个共性的取出元素的抽象方法。这个方法就是Collection接口中的iterator()方法,Collection集合的子类通过调用此方法,就可以获取Iterator迭代器对象,通过Iterator迭代器就可以完成取出元素的操作。
Iterator迭代器是由集合中的内部类实现的,每个集合的内部数据结构不同,集合通过调用iterator()方法,iterator()方法中,创建了实现Iterator接口的内部类对象。并返回这个对象,内部类中覆写了Iterator接口中的元素取出方法,如:hasNext(),itNext(),建立集合自己的元素取出方式。
14.4 List<E>集合
List集合特点:允许元素重复,有序(元素存入和取出顺序一致)
常用子类:
Vector 集合特点:jdk 1.0,不常用,内部是数组数据结构,是同步的,线程安全,效率低。支持包括null在内的所有元素。(被ArrayList替代)。
ArrayList集合特点:jdk 1.2 ,内部是可变长度数组数据结构,不同步,增删慢,但查询速度快。支持包括null在内的所有元素。
LinkedList集合特点:jdk 1.2 ,内部是链表数据结构,不同步,增删快,但查询速度慢。支持null及所有元素。
1. Vector集合
Vector内部是数组数据结构,可变长度数组,这个集合,多线程是同步的,所以效率会低一些,现在,很少用到,此集合有一个元素取出的特有方式就是Enumeration<E>枚举,通过调用elements()方法,返回Enumeration<E>对象,再调用枚举对象的方法,取出元素,同样这个集合也具有iterator()和listIterator()两种迭代器。对于此集合来说,有三种元素的取出方。
示例代码:
import java.util.Enumeration;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
//1,创建Vector集合
Vector<String> vector=new Vector<String>();
//2,添加String类型的元素
vector.add("abc1");
vector.add("abc2");
vector.add("abc3");
vector.add("abc4");
//3,取出元素
for(Enumeration<String> en=vector.elements();en.hasMoreElements();){
String s=en.nextElement();
System.out.println("集合元素:"+s);
}
}
}
/*
集合元素:abc1
集合元素:abc2
集合元素:abc3
集合元素:abc4
*/
Iterator和listIterator有什么不同?
Iterator迭代器对象,只能遍历或取出集合中的元素,而listIterator迭代器,可以实现在遍历或取出元素的同时,对集合进行修改,增加,删除等操作,并且可以从后往前遍历或取出集合元素。
如:
import java.util.ListIterator;
import java.util.Vector;
public class VectorDemo {
public static void main(String[] args) {
//1,创建Vector集合
Vector<String> vector=new Vector<String>();
//2,添加String类型的元素
vector.add("abc1");
vector.add("abc2");
vector.add("abc3");
vector.add("abc4");
//3,取出元素,使用ListIteraor迭代器
for(ListIterator<String> li=vector.listIterator();li.hasNext();){
String s=li.next();
li.set("abc5");//取出元素的同事,修改集合元素。
System.out.println("集合元素:"+s);
}
System.out.println(vector.toString());
}
}
/*
集合元素:abc1
集合元素:abc2
集合元素:abc3
集合元素:abc4
[abc5, abc5, abc5, abc5]
*/
2. ArrayList集合
此集合内部是数组数据结构,是可变长度数组,不支持线程同步所以效率要高一些,此集合的出现目的就是替代Vector集合,因为内部是数组数据结构,所以,元素的查询速快,但元素的增删速度慢。ArrayList集合的元素取出可以通过调用,iterator()和listIterator()方法,获取Iterator和ListIterator两个迭代器对象,再通过迭代器对象取出元素。
如:
import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;
public class ArrayListDemo {
public static void main(String[] args) {
//1,创建ArrayList集合
ArrayList<String> al=new ArrayList<String>();
//2,添加String类型的元素
al.add("abc1");
al.add("abc2");
al.add("abc3");
al.add("abc4");
//3,取出元素,使用Iteraor迭代器
for(Iterator<String>it=al.iterator();it.hasNext();){
String s=it.next();
System.out.println("集合元素:"+s);
}
}
}
/*
集合元素:abc1
集合元素:abc2
集合元素:abc3
集合元素:abc4
*/
3,LinkedList集合
此集合内部是链表数据结构,不支持线程同步,因为内部数据结构的原因,其增删元素的速度快,但查询速度慢。
元素的取出也可以通过调用iterator()和listIterator()方法,获取迭代器对象Iterator和listIterator,通过对象的元素取出方法,取出元素。
如:
import java.util.Iterator;
import java.util.LinkedList;
public class ArrayListDemo {
public static void main(String[] args) {
//1,创建LinkedList集合
LinkedList<Integer> link=new LinkedList<Integer>();
//2,添加String类型的元素
link.add(123);
link.add(345);
link.add(456);
link.add(789);
//3,取出元素,使用ListIteraor迭代器
for(Iterator<Integer>it=link.iterator();it.hasNext();){
Integer i=it.next();
System.out.println("集合元素:"+i);
}
}
}
/*
集合元素:123
集合元素:345
集合元素:456
集合元素:789
*/
练习:去除ArrayList集合中重复的元素。
思路:
1,因为ArrayList集合中的元素是允许重复的。
2,可以,再创建一个临时的ArrayList集合,遍历ArrayList集合,通过临时的ArrayList集合调用contains()判断,这个空集合,是否包含遍历的元素,如果包含就不添加,否则,添加到临时的集合中。返回临时的集合,获取一个不含重复元素的ArrayList集合。
如:
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListDemo {
public static void main(String[] args) {
//创建集合
ArrayList<String>al=new ArrayList<String>();
//添加元素
al.add("abc1");
al.add("abc2");
al.add("abc2");
al.add("abc1");
al.add("abc4");
al.add("abc5");
//调用去除重复元素的方法
ArrayList al1=deleteElements(al);
//打印去除重复元素后的集合
System.out.println("去出重复元素后:"+al1);
}
public static ArrayList deleteElements(ArrayList<String> al) {
//1,创建临时容器ArrayList
ArrayList<String> temp=new ArrayList<String>();
//2,遍历包含元素的集合
for (String s:al) {
if(!temp.contains(s)){//contains()方法,实际是调用了equals()方法
temp.add(s);//不包含时,就添加到临时集合ArrayList中。
}
}
return temp;
}
}
//去出重复元素后:[abc1, abc2, abc4, abc5]
14.5 Set<E>集合
Set集合的特点:不允许元素重复(与List集合相反),保证元素的唯一性,无序(存取顺序一致或不一致。LinkedHashSet可维持存取顺序一致,TreeSet集合可以对元素进行自然排序,但元素本身要实现Comparable接口)
常用子类:
HashSet集合特点:jdk 1.2内部是哈希表数据结构,不同步,允许null元素。此集合通过内部的哈希算法来确定元素的存储位置,因为不允许元素重复,所以,每存入一个元素都会与前一次存入的元素进行比较,是通过调用元素的hashCode()方法和equals()方法来进行比较的。(这里要注意的是:equals()方法比较的是内容,而不是地址,所以当在HashSet集合中存入自定义元素时,如果要保证元素的唯一性,必须要覆写hashCode()方法和equals()方法。)
LinkedHashSet集合:LinkedHashSet是HashSet的子类,能保证存取顺序一致。允许null元素。
TreeSet集合特点:jdk 1.2内部是二叉树数据结构,不同步,允许null元素。TreeSet与HashSet集合中的hashCode(),equals()方法无关。TreeSet集合可以对元素进行自然排序,因为 TreeSet集合是通过调用元素的compareTo()方法来,进行排序和判断元素是否相同的,而compareTo()方法是由元素内部实现Comparable接口,并覆写compareTo()完成的。所以TreeSet集合中的元素,必须要实现Comparable接口,覆写 CompareTo()方法,常用的类一般都实现了Comparable接口,例:如果在TreeSet集合中存储自定义对象,那么这个自定义的类必须要实现Comparable接口,并且覆写CompareTo方法,使其具有比较性。
1,HashSet集合
内部是哈希表数据结构,每次添加一个元素,都会调用元素的hashCode()方法,获取元素的哈希值确定元素的存储位置,如果有两个元素的哈希值相同,会再次调用equals()方法,比较这两个元素的内容,如果内容不同,会延伸位置存储,相同则不存。Java自身的类内部已经完成了对hashCode()和equals()方法的覆写,所以不需要再进行覆写。而对于自定义的一些类,作为元素存储到HashSet时,必须要覆写这两个方法。
为什么自定义的类必须覆写hashCode()和equals()方法呢?
因为,Java中所有的类都继承Object类,如果自定义的类没有覆写hashCode()和equals(),那么使用的就是Object类中的hashCode()和equals()方法,Ojbect类中的这两个方法,是内部实现的。而覆写的目的是建立自定义类的自身的hashCode()和equals().
如:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<String> hs=new HashSet<String>();
hs.add("abc1");
hs.add("abc1");//添加重复元素
hs.add("abc2");
hs.add("abc3");
hs.add("abc4");
for (Iterator<String> it=hs.iterator();it.hasNext();) {
String str=it.next();
System.out.println(str);
}
}
}
/*
打印结果:
abc1
abc4
abc2
abc3
*/
集合中存储的String类型元素,重复的元素无法添加到集合中。这是因为,String内部实现了hashCode()和equals()的覆写。
HashSet存储自定义对象:
如:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<Person> hs=new HashSet<Person>();
hs.add(new Person("lisi",24));
hs.add(new Person("lisi",24));//添加重复元素
hs.add(new Person("zhangsan",23));
hs.add(new Person("zhangsan",23));//添加重复元素
hs.add(new Person("xiaoqiang",20));
hs.add(new Person("wangwu",21));
for (Iterator<Person> it=hs.iterator();it.hasNext();) {
Person p=it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
class Person{//自定义Person类
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
}
/*
打印结果:
zhangsan::23
wangwu::21
zhangsan::23
lisi::24
lisi::24
xiaoqiang::20
可见,重复元素也被添加进了HashSet集合
*/
HashSet集合中存储的自定义对象Person,为什么可以重复呢?因为自定义的Person类中,并没有覆写hashCode()和equals()方法,而是直接调用了父类Object类中的hashCode(),equals()方法,Object类的hashCode()是获取对象的哈希值,而每次new的对象,哈希值都是不一样的,且Object类中的equals()方法比较也是对象的地址,所以,虽然在HashSet集合存储了具有相同内容的对象,但是他们的哈希值和地址都是不同的,所以当HashSet集合在调用Person的hashCode()和equals()实际上是调用了Object中的这两个方法,因为值得不同,所以认为是不同的元素。
可见,对于自定义对象要想保证元素不重复,就要覆写Object类的hashCode()和equals()方法,建立自定义元素的特有比较方式。
如:
import java.util.HashSet;
import java.util.Iterator;
public class HashSetDemo {
public static void main(String[] args) {
HashSet<Person> hs=new HashSet<Person>();
hs.add(new Person("lisi",24));
hs.add(new Person("lisi",24));//添加重复元素
hs.add(new Person("zhangsan",23));
hs.add(new Person("zhangsan",23));//添加重复元素
hs.add(new Person("xiaoqiang",20));
hs.add(new Person("wangwu",21));
for (Iterator<Person> it=hs.iterator();it.hasNext();) {
Person p=it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
class Person{//自定义Person类
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
public int hashCode(){//覆写hashCode方法,通过年龄和姓名的哈希值进行比较。
return this.age+name.hashCode()*37;
}
public boolean equals(Object obj){//覆写equals()方法,对姓名和年龄进行比较。
if(this==obj)
return true;
if(!(obj instanceof Person))
throw new ClassCastException("类型不匹配!");
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
}
/*
打印结果:
zhangsan::23
wangwu::21
xiaoqiang::20
lisi::24
可见,重复元素没有被添加。
*/
总结:HashSet集合存储自定义类型的元素时,要覆写hashCode()和equals()方法,完成自定义类型元素的特有比较方式,保证存储到HashSet集合中的唯一性。否则,不能保证唯一性。
2.LinkedHashSet集合
LinkedHashSet集合是HashSet的子类,此集合可以保证Set集合的有序性,实现元素的存和取的顺序一致。其他与hashSet集合相同。
如:
import java.util.Iterator;
import java.util.LinkedHashSet;
public class HashSetDemo {
public static void main(String[] args) {
LinkedHashSet<String> lhs=new LinkedHashSet<String>();
lhs.add("abc1");
lhs.add("abc2");
lhs.add("abc3");
lhs.add("abc4");
lhs.add("abc5");
for (Iterator<String> it=lhs.iterator();it.hasNext();) {
String str=it.next();
System.out.println(str);
}
}
}
/*
打印结果:
abc1
abc2
abc3
abc4
abc5
元素的存入顺序和取出顺序一致。
*/
3.TreeSet集合
此集合是内部二叉树数据结构,集合可以实现对元素的自然排序,前提是元素必须实现Comparable接口,那些已经实现Comparable接口,并覆写了compareTo()方法的java类,就已经具备了比较性,但是自定义的元素,必须要实现Comparable接口,并覆写compareTo()方法,TreeSet集合与元素的hashCode()和equals()方法无关。
TreeSet集合中对元素进行排序的两种方式:
(1)自定义元素实现Comparable接口,覆写compareTo()方法,建立自定义元素的特有排序特点。这里要注意元素比较的主要条件和次要条件,都进行判断。
如:存储自定义对象Person
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.TreeSet;
public class HashSetDemo {
public static void main(String[] args) {
TreeSet<Person> ts=new TreeSet<Person>();
ts.add(new Person("lisi",23));
ts.add(new Person("zhangsan",20));
ts.add(new Person("wangwu",29));
ts.add(new Person("xiaoqiang",27));
for (Iterator<Person> it=ts.iterator();it.hasNext();) {
Person p=it.next();
System.out.println(p.getName()+"::"+p.getAge());
}
}
}
class Person implements Comparable{//自定义Person类实现Comparable接口
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public int compareTo(Object o) {//覆写compareTo()方法
Person p=(Person)o;
int temp=this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;//先判断年龄,年龄相同,再比较姓名。
}
}
/*
打印结果:
zhangsan::20
lisi::23
xiaoqiang::27
wangwu::29
按照年龄进行了排序。
*/
(2)如果某些自定义的元素,不能被操作,因为TreeSet集合的构造函数中,可以传入实现了Comparator接口的自定义比较器,可以让集合具备比较性,对元素进行排序。
如:
import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Person> ts=new TreeSet<Person>(new CompByAge());//要让集合具有比较性,必须传入比较器
ts.add(new Person("lisi",23));
ts.add(new Person("zhangsan",20));
ts.add(new Person("wangwu",29));
ts.add(new Person("xiaoqiang",27));
for(Iterator<Person> it=ts.iterator();it.hasNext();){
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
}
class Person{//自定义Person类,并没有实现Comparable接口
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
}
class CompByAge implements Comparator<Person>{//自定义一个比较器
@Override
publicint compare(Person o1, Person o2) {
int temp=o1.getAge()-o2.getAge();
return temp==0?o1.getName().compareTo(o2.getName()):temp;//定义比较的主要次要条件。
}
}
/*
打印结果:
zhangsan:20
lisi:23
xiaoqiang:27
wangwu:29
*/
总结:TreeSet集合排序方法和判断元素是否相同可以有两种方式:
(1)让元素具备比较性,就要元素去实现Comparable接口并覆写CompareTo()方法。
(2)如果元素不是自己定义的,比如一个Person类,那么如果这个Person类没有去实现Comparable接口,这样Person对象就不具备比较性,这种情况我们可以采取第二种方式,就是让TreeSet集合具备比较性,因为TreeSet集合的构造函数中,可以传入比较器参数,所以我们可以自定义一个类并实现Comparator接口,这样就自定义了一个比较器,把这个比较器作为参数传递给TreeSet集合的构造函数,实现对元素的比较,完成排序。
14.6 Map<K,V>集合
Map集合是双列集合,集合中元素都是以键值对的形式存在的,且Map集合中必须保证键是唯一的,如果有相同的键存在,则值会被覆盖。
常用子类:
Hashtable:内部是哈希表数据结构,此集合不支持空键和空值,线程是同步的,所以相对效率要低,很少用到。
Hashtable子类Properties:此集合特点:1,键和值都是字符串类型。2,可以结合IO流使用,从流上获取数据和把集合中的数据保存到流上。
HashMap:内部是哈希表数据结构,支持空键和空值,线程不同步,效率高。
TreeMap:内部是二叉树数据结构,支持空键和空值,线程不同步。
1,Properties集合
此集合中键和值必须是字符串类型,没有泛型声明,元素的添加可以使用其特定的方法,setProperty(String key,String value);元素的取出可以使用其特定方法,stringPropertyNames()此方法返回一个Set<String key>集合的键集,再通过getProperty(String key),获取键对应的值。Properties集合,多用于对键值对形式的配置文件操作,因为它可以结合IO流,通过自己的特有方法,load()和store()方法,从字节或字符流上获取数据到集合,也可以集合中的数据保存在字节流或字符流上,实现持有化存储。
如:读取一个配置文件,修改后,再进行存储。
/*
zhangsan=23
lisi=34
wangwu=30
zhaoliu=20
xiaoqiang=24
*/
以上是配置文件信息,现在通过Properties将xiaoqiang的值改为:30
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
//需求:读取一个配置文件,修改信息后,再存储到文件中。
publicclass Properties练习 {
publicstaticvoid main(String[] args) throws IOException {
modifiConfile("d:\\confile.properties");
}
publicstaticvoid modifiConfile(String filename) {
//1,将接收的字符串路径封装成File对象
File file=new File(filename);
//2,创建一个Properties集合
Properties prop=new Properties();
//3,对字符流初始化
BufferedReader br=null;
BufferedWriter bw=null;
try {
br=new BufferedReader(new FileReader(file));
prop.load(br);//从字符流上获取关联的配置文件数据
prop.setProperty("xiaoqiang", "30");//修改xiaoqiang的值为30
bw=new BufferedWriter(new FileWriter(file));//创建字符输出流
prop.store(bw, "name+age");//将修改后的数据再保存到流上,更改配置文件信息。
} catch (IOException e) {
e.printStackTrace();
}finally{
if(bw!=null)
try {
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
if(br!=null)
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/*
修改后的配置文件信息
#name+age
#Thu Oct 24 22:29:38 CST 2013
xiaoqiang=30
zhangsan=23
lisi=34
zhaoliu=20
wangwu=30
*/
2,HashMap<K,V>集合
此集合内部是哈希表数据结构,为了保证键的唯一性,需要调用键的hashCode()和equals()方法,比如一些自定的元素,则必须要完成对 hashCode()和equals()方法的覆写,否则不能保证键的唯一性。此集合与Hashset集合相似,其实HashSet内部就是调用了HashMap的细节操作。
元素的添加可以使用put(k,v),元素的取出可以调用keySet()或entrySet()方法,返回一个包含键或包含键值对的Set集合,再过Set集合的迭代器取出元素。
如:存储自定义对象Person
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Person,String> hm=new HashMap<Person,String>();
hm.put(new Person("lisi",23),"北京");
hm.put(new Person("lisi",23),"北京");//存储了重复的元素。
hm.put(new Person("zhangsan",20),"上海");
hm.put(new Person("wangwu",29),"南京");
hm.put(new Person("xiaoqiang",27),"重庆");
for(Iterator<Map.Entry<Person,String>>it=hm.entrySet().iterator();it.hasNext();){//取出集合中的元素
Map.Entry<Person, String> me=it.next();
Person key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+":"+value);
}
}
}
class Person{//自定义Person类
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
}
/*
打印结果:
wangwu:29:南京
lisi:23:北京
zhangsan:20:上海
xiaoqiang:27:重庆
lisi:23:北京
这里可以发现,出现了同样的键。
*/
HashMap集合中存储了相同的自定义元素,为什么键不能保证唯一呢?
这是因为HashMap要保证键的唯一性,必须要覆写hashCode()和equals()方法。所以,Person类中必须要完成对Object类中这两个方法的覆写,建立自定义Person对象元素的特定比较方式。
如:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
HashMap<Person,String> hm=new HashMap<Person,String>();
hm.put(new Person("lisi",23),"北京");
hm.put(new Person("lisi",23),"北京");//存储了重复的元素。
hm.put(new Person("zhangsan",20),"上海");
hm.put(new Person("wangwu",29),"南京");
hm.put(new Person("xiaoqiang",27),"重庆");
for(Iterator<Map.Entry<Person,String>>it=hm.entrySet().iterator();it.hasNext();){//取出集合中的元素
Map.Entry<Person, String> me=it.next();
Person key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+":"+value);
}
}
}
class Person{//自定义Person类
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
public int hashCode() {//覆写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) {//覆写equals()
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;
} elseif (!name.equals(other.name))
return false;
return true;
}
}
/*
打印结果:
xiaoqiang:27:重庆
zhangsan:20:上海
wangwu:29:南京
lisi:23:北京
没有重复的键,保证了键的唯一性。
*/
3,TreeMap<K,V>集合
此集合内部是二叉树数据结构,可以实现对键的自然排序,但是如果是自定义的元素必须要实现Comparable接口,覆写compareTo()方法,或者,自定义比较器,实现Comparator接口,覆写compare()方法,传给TreeMap构造函数。才能完成对自定义元素的排序。
(1) 自定义元素实现Comparable接口,覆写compareTo()方法,让元素具备比较性。
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Person,String>ts=new TreeMap<Person,String>();
ts.put(new Person("lisi",23),"北京");
ts.put(new Person("zhangsan",20),"上海");
ts.put(new Person("wangwu",29),"南京");
ts.put(new Person("xiaoqiang",27),"重庆");
for(Iterator<Map.Entry<Person,String>>it=ts.entrySet().iterator();it.hasNext();){//取出集合中的元素
Map.Entry<Person, String> me=it.next();
Person key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+":"+value);
}
}
}
class Person implements Comparable<Person>{//自定义Person类实现Comparable接口
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
@Override
publicint compareTo(Person o) {//覆写compareTo方法
int temp=this.getAge()-o.getAge();
return temp==0?this.getName().compareTo(o.getName()):temp;//先比较年龄,再比较姓名
}
}
/*
打印结果:
zhangsan:20:上海
lisi:23:北京
xiaoqiang:27:重庆
wangwu:29:南京
*/
(2) 自定义比较器,作为参数传递给TreeMap的构造函数,让集合具备比较性.
。
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;
public class TreeMapDemo {
public static void main(String[] args) {
TreeMap<Person,String>ts=new TreeMap<Person,String>(new Comparator<Person>(){
@Override
publicint compare(Person o1, Person o2) {
int temp=o1.getAge()-o2.getAge();
return temp==0?o1.getName().compareTo(o2.getName()):temp;
}});//这里直接使用匿名内部类,创建Comparator接口子类对象,并覆写compare方法。
ts.put(new Person("lisi",23),"北京");
ts.put(new Person("zhangsan",20),"上海");
ts.put(new Person("wangwu",29),"南京");
ts.put(new Person("xiaoqiang",27),"重庆");
for(Iterator<Map.Entry<Person,String>>it=ts.entrySet().iterator();it.hasNext();){//取出集合中的元素
Map.Entry<Person, String> me=it.next();
Person key=me.getKey();
String value=me.getValue();
System.out.println(key.getName()+":"+key.getAge()+":"+value);
}
}
}
class Person{//自定义Person类
private int age;
private String name;
public int getAge() {
return age;
}
public String getName() {
return name;
}
Person(String name,int age){
this.name=name;
this.age=age;
}
}
/*
打印结果:
zhangsan:20:上海
lisi:23:北京
xiaoqiang:27:重庆
wangwu:29:南京
*/
总结:集合是用来存储对象的不同的集合其内部数据结构的不同,元素的操作方式也不同,单例集合中:List及其子类允许元素重复,Set集合不允许元素重复,Map要保证键的唯一。他们都有各自的判断元素是否相同的方式。其中Set集合的TreeSet,HashSet和 Map 集合的TreeMap,HashMap很相似,只是一个单例集合,一个是双例集合,元素保证唯一的方式基本一样。
---------------------- ASP.Net+Android+IOS开发、 .Net培训、期待与您交流! ----------------------