Java集合的使用
一、Java集合的概念
java集合又称为java容器,主要用于在程序中存放对象,而且只能存放对象或者集合,不能存放基本数据类型。
二、容器API
J2SDK所提供的容器API位于java.util包内,集合API的类图结构如下图所示:
其中,Collection集合是一个一个的往里边装,图中的“重复”指的是两个对象之间equals,Map这种容器是一对一对的往里边装。
三、Collection接口
- Set和List分别定义了存储方式,Set中的数据对象没有顺序且不可以重复,List中的数据对象有顺序且可以重复。
- Map接口定义了存储“键——值映射对”的方法
- Collection接口中所定义的方法:
int size//装了多少个元素或者对象
boolean isEmpty()//是否为空
void clear()//清空
boolean contains(Object element)//是否包含某个对象(包含的意思是传递的参数equals某一个内部的元素)
boolean add(Object element)//添加对象
boolean remove(Object element)//删除对象
Iterator iterator//迭代器
boolean containsAll(Collection c)//是不是包含一个集合里面的所有元素
boolean addAll(Collection c)//添加一个集合
boolean removeAll(Collection c)//删除集合
boolean retainAll(Collection c)//求当前集合类和集合c的交集
Object[] toArray()//把里面装的每个对象全部转化为一个Object类型的数组
四、equals方法和hashcode方法的重写
容器类对象在调用remove、contains等方法时需要比较对象是否相等,这会涉及到对象类型的equals方法和hashcode方法;对于自定义的类型,需要重写equals和hashcode方法以实现自定义的对象相等规则。
注意:相等的对象应该具有相等的hashcode,重写equals方法必须重写hashcode方法。当对象在Map里面作为一对往Map里面装,这个对一个叫“键(key)”,一个叫“值(value)”,当这个对象作为“键”的时候,hashcode是有用的。总而言之,就是重写对象的equals方法必须重写对象的hashcode方法,两个对象equals,则必须具有相同的hashcode(hash码)。
示例如下:
public class BaseContainer {
public static void main(String[] args) {
Collection c = new HashSet();
c.add("hello");
c.add(new Name("f1","l1"));
c.add(new Integer(100));
c.remove("hello");
c.remove(new Integer(100));
System.out.println(c.remove(new Name("f1","l1")));
System.out.println(c);
}
}
class Name{
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Name{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
/**
* 重写equals方法
* @param obj 对象
* @return 两个对象的比较结果,只有“我的名字”等于你传递给我的name对象的名字才返回true
*/
@Override
public boolean equals(Object obj) {
if(obj instanceof Name){
Name name = (Name) obj;
return firstName.equals(name.firstName)
&& lastName.equals(name.lastName);
}
return super.equals(obj);
}
/**
* 重写hashcode方法
* @return 暂时使用字符串的hashcode方法(也可以自己实现,但是稍微复杂,可以自己研究下)
*/
@Override
public int hashCode() {
return firstName.hashCode();
}
}
输出结果:
由于String类和Integer类已经重写了equals和hashcode方法,故执行remove方法,会比较传入的对象和集合中的对象是否equals,如果equals,则将集合中的元素移除,而Name类,如果不重写equals方法和hashcode方法,则代码执行的结果如下图所示:
五、Iterator接口
- 所有实现了Collection接口的容器类都有一个iterator方法用以返回一个实现了iteration接口的对象。
- iterator对象称作迭代器,用以方便的实现对容器内元素的遍历操作。
- iterator接口定义了如下方法:
boolean hasNext();//判断游标右边是否有元素
Object next();//返回游标右边的元素并将游标移动到下一个位置
void remove();//删除游标左边的元素,在执行完next之后该操作只能执行一次
- iterator对象的remove方法是在迭代过程中删除元素的唯一安全的方法。
总之,iterator就是一个统一的来遍历collection里面所有元素的方法。
示例如下:
public class IteratorTest {
public static void main(String[] args) {
Collection c = new HashSet();
c.add(new Name("f1","l1"));
c.add(new Name("f2","l2"));
c.add(new Name("f3","l3"));
Iterator iterator = c.iterator();
while (iterator.hasNext()){
Name name = (Name) iterator.next();
if(name.equals(new Name("f1","l1"))){
iterator.remove();
}
}
System.out.print(c);
}
}
class Name {
private String firstName;
private String lastName;
public Name(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
@Override
public String toString() {
return "Name{" +
"firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
/**
* 重写equals方法
*
* @param obj 对象
* @return 两个对象的比较结果,只有“我的名字”等于你传递给我的name对象的名字才返回true
*/
@Override
public boolean equals(Object obj) {
if (obj instanceof Name) {
Name name = (Name) obj;
return firstName.equals(name.firstName)
&& lastName.equals(name.lastName);
}
return super.equals(obj);
}
/**
* 重写hashcode方法
*
* @return 暂时使用字符串的hashcode方法(也可以自己实现,但是稍微复杂,可以自己研究下)
*/
@Override
public int hashCode() {
return firstName.hashCode();
}
}
输出结果如下:
可以看到成功删除了名字为f1,l1的对象(因为使用的hashset集合,有可能输出的顺序和上面的不一致),需要注意的是在边遍历边删除多个集合元素过程中不能使用for循环或者增强for循环,因为在删除过程中,集合的元素个数已经发生了变化,而使用iterator可以正常删除元素,使用for循环倒序遍历也可以实现元素的删除。无论是使用哪种方式,删除一个对象都必须要重写equals方法和hashcode方法,否则无法删除元素!