Java集合-1(List,Map,Set)
java集合和C++的STL容器类似,方便程序员管理数据,操作数据(以下有些内容借鉴了廖雪峰老师的博客:廖雪峰老师的网站,这里总结了常用的内容,完善了一些例程)
java集合主要有三类:
List:列表,包括线性表和链表,类似C++的vector和list
Map: 键值对集合
Set: 一种保证没有重复元素的集合
java的集合类都由java.util包提供
List集合
- List只是接口,其常用实现类有两个:ArrayList和LinkedList。前者是线性表,后者是链表。定义一个List对象:
List<String> list = new ArrayList<>();
- List提供的常用方法:
void add(E e); //在List集合尾部添加元素
void add(int index, E e) //在List指定位置添加元素
void remove(int index) //删除指定位置元素
E get(int index) //获取指定位置元素
int size() //获取集合大小
boolean contains(E e) //查看集合内是否有指定元素
- 在使用contains函数时,需要注意:当List集合中存放的元素时自定义类的对象时,需要在自定义类中实现equals()函数。
boolean equals(Object o)
其原因也比较好理解,contains函数在判断一个元素是否在集合中时,需要进行比较,比较时会调用equals函数,标准库中的String类,Integer类都实现了equals函数。下面是一个例子。
/**
* 首先定义Person类,放在Person.java文件中
**/
public class Person{
public String name;
public int age;
public Person(String name,int age){
this.name = name;
this.age = age;
}
//实现equals函数
public boolean equals(Object o) {
System.out.println("equals function was used");
if(o instanceof Person) {
Person p = (Person)o;
if(p.name == this.name && p.age == this.age) {
return true;
}
}
return false;
}
}
********************************************************************************************
/**
* 主函数实现
**/
import java.util.*;
public class ListPractice{
public static void main(String[] args) {
List<Person> persons = new ArrayList<>();
persons.add(new Person("gong",20));
persons.add(new Person("guan",19));
//调用contains函数
System.out.println(persons.contains(new Person("gong",20)));
}
}
最后运行结果:
程序运行结果中打印 了“equals function was used”,表示在Person类中的equals函数被调用了。
Map集合
- Map只是一个接口,其常用实现类有三个:HashMap,EnumMap,TreeMap。定义一个Map:
Map<String,int> m = new HashMap<>();
- Map提供的常用方法:
Value put(Key k, Value v); //向Map中插入键值对
Value get(Key k); //根据键,获取值,如果键不存在,则返回null
boolean containsKey(Key k); //查看某个键是否在集合中
使用put方法向Map中插入键值对时,如果Key已存在,则新的键值对将覆盖旧的键值对,而旧键值对的值会作为返回值返回;否则put的返回值为null.
- Map对象有两个重要成员:keySet和entrySet。前者为所有键值的集合,后者为所有键值对的集合,可以用这两个成员来对Map进行遍历。例程如下:
import java.util.*;
public class MapPractice{
public static void main(String[] args) {
Map<String,Integer> m = new HashMap<>();
m.put("gong",26);
m.put("guan",25);
//利用keySet遍历Map
System.out.println("use keySet");
for(String key : m.keySet()) {
System.out.println(key + ":" + m.get(key));
}
//利用entrySet遍历Map
System.out.println("use entrySet");
for(Map.Entry<String, Integer> entry : m.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
}
}
- 使用HashMap时需要注意,如果Key为自定义类,则需要在自定义类中实现以下两个方法:
boolean equals(Object o) //判断两个键值是否匹配
int hashCode() //定义hash值计算规则
java标准库中的String类,Integer类等,都实现了以上两个方法。例子如下:
/**
* ID.java
* 首先定义ID类,在该类中实现equals()方法和hashCode()方法
**/
public class ID{
public int id;
public ID(int id) {
this.id = id;
}
//实现equals函数
public boolean equals(Object o) {
//equals函数被调用时打印
System.out.println(this.id + " equals function has been used");
if(o instanceof ID) {
ID i = (ID)o;
if(i.id == this.id) {
return true;
}
}
return false;
}
//实现hascode方法
public int hashCode() {
//hashCode()函数被调用时打印
System.out.println(this.id + " hasCode function has been used");
return this.id;
}
}
****************************************************************************************
/**
* 主函数
**/
import java.util.*;
public class MapPractice{
public static void main(String[] args) {
//使用ID类作为键,String作为值
Map<ID,String> m = new HashMap<>();
m.put(new ID(1),"gong");
m.put(new ID(2),"huan");
System.out.println("ID = 1 : " + m.get(new ID(1)));
}
}
程序运行结果如下:
从运行结果可以看出,在使用put()函数插入键值对时,会调用hashCode()函数来计算hash值。在使用get()函数时,会先调用hashCode计哈希值,然后调用equals函数匹配键值
EnumMap貌似用的不多,这里先省略,可以查看廖雪峰老师的介绍(EnumMap)
- TreeMap。HashMap中键值的存放时无序的,而TreeMap中键值的存放是有序的,原因是TreeMap底层用红黑树实现。使用TreeMap是,除了Map提供的常用方法外,还常用以下两个函数:
Object firstKey() //获取第一个键值(即最小的键值)
Object lastKey() //获取最后一个键值(即最大的键值)
如果使用TreeMap时,键为自定义类,则需要:
- 自定义类继承Comparable接口(在java.lang包中)
- 在自定义类中重写compare方法(不用实现equals方法和hashCode方法,当然实现了也没有问题)。
int compareTo(Object o) //大于返回1;小于返回-1;相等返回0
使用自定义类作为键值的例子如下:
/**
* ID.java
* 定义ID类,继承Comparable接口,实现compareTo方法
**/
import java.util.*;
import java.lang.*;
public class ID implements Comparable{
public int id;
public ID(int id) {
this.id = id;
}
public int compareTo(Object o) {
System.out.println(this.id + " compareTo function has been used");
if(o instanceof ID) {
ID i = (ID)o;
if(this.id > i.id) {
return 1;
}
if(this.id < i.id) {
return -1;
}
}
return 0;
}
}
*************************************************************************
/**
* 主函数
**/
import java.util.*;
public class MapPractice{
public static void main(String[] args) {
Map<ID,String> m = new TreeMap<>();
m.put(new ID(1),"gong");
m.put(new ID(2),"huan");
System.out.println("ID = 1 : " + m.get(new ID(1)));
}
}
上述代码的运行结果如下:
可以看出,compareTo函数确实被调用了。
Set集合
- Set集合中的元素时不重复的。Set只是接口,其常用实现类有两个:HashSet和TreeSet。这HashMap,TreeMap类似,前者底层数据结构时哈希表,元素存放是无序的;后者底层数据结构时红黑树,元素存放是有序的。
- Set集合常用的方法:
boolean add(E e) //向Set添加元素
boolean remove(E e) //从Set中删除元素
boolean contains(E e) //判断集合中是否包含指定元素
- 使用HashSet时,如果集合存放元素为自定义类,则需要实现equals()函数和hashCode()函数。(和HashMap中的Key很相似)
例如:
/**
* Person.java
* 实现Person类,实现equals函数和hashCode函数
**/
import java.lang.*;
public class Person{
public int id;
public Person(int id) {
this.id = id;
}
//实现equals方法
public boolean equals(Object o) {
System.out.println("equals function has been used");
if(o instanceof Person) {
Person p = (Person)o;
if(p.id == this.id) {
return true;
}
}
return false;
}
//实现hashCode方法
public int hashCode() {
System.out.println("hashCode function has been used");
return this.id;
}
}
*********************************************************************************
/**
* 主函数
**/
import java.util.*;
public class SetPractice{
public static void main(String[] args) {
Set<Person> persons = new HashSet<>();
persons.add(new Person(1));
persons.add(new Person(1));
persons.add(new Person(2));
System.out.println("persons.size() = " + persons.size());
for(Person p : persons) {
System.out.println("Person id = " + p.id);
}
}
}
上面代码的运行结果如下:
可见,equals函数和hashCode函数确实被调用了,而且主函数向Set集合中添加了三个Person对象(其中两个Person对象的id相同),最后集合中只有两个id值不同的Person对象。
- 使用TreeMap时,如图集合中存放元素为自定义类,则该类需要继承Comparable接口,实现compareTo函数。(和TreeMap中的Key相同)
例子如下:
/**
* Person.java
* 实现CompareTo函数
**/
import java.lang.*;
public class Person implements Comparable{
public int id;
public Person(int id) {
this.id = id;
}
//实现compareTo函数
public int compareTo(Object o) {
System.out.println("compareTo function has been used");
if(o instanceof Person) {
Person p = (Person)o;
if(this.id > p.id) {
return 1;
}
if(this.id < p.id) {
return -1;
}
}
return 0;
}
}
************************************************************************
/**
* 主函数
**/
import java.util.*;
public class SetPractice{
public static void main(String[] args) {
Set<Person> persons = new TreeSet<>();
persons.add(new Person(1));
persons.add(new Person(1));
persons.add(new Person(2));
System.out.println("persons.size() = " + persons.size());
for(Person p : persons) {
System.out.println("Person id = " + p.id);
}
}
}
上面代码的运行结果如下: