黑马程序员技术交流社区

标题: 关于ArrayList、hashset和hashcode的用法? [打印本页]

作者: 途遥子若    时间: 2013-12-18 10:19
标题: 关于ArrayList、hashset和hashcode的用法?
Collection coll=new ArrayList( );       /* Collection coll2=new HashSet ( );*/
ReflectPoint pt1=new ReflectPoint(3,3);
ReflectPoint pt2=new ReflectPoint(5,5);
ReflectPoint pt3=new ReflectPoint(3,3);
coll.add(pt1);   coll.add(pt2);    coll.add(pt3);    coll.add(pt1);
/*coll2.add(pt1);   coll2.add(pt2);    coll2.add(pt3);    coll2.add(pt1);*/
这两个的执行结果为什么不一样?请说说ArrayList和HashSet的区别,还有ArrayList、hashset和hashcode的用法,并举例

作者: 王琪    时间: 2013-12-18 13:09

2. List(Collection的一个子接口——允许重复且有序)的新增的主要方法视图:
[java] view plaincopy

//1.在指定的位置上添加一个元素  
public void add(int index, E element);  
//2.取得指定位置上的元素  
public E get(int index);  
//3.修改指定位置上的元素,返回原先的元素  
public E set(int index, E element);  
//4.为ListIterator接口实例化  
public ListIterator<E> listIterator();  
//5.删除指定位置上的元素,返回删除的那个元素的引用  
public E remove(int index);  

2.1 新的子类:ArrayList
[java] view plaincopy

public class ArrayList<E> extends AbstractList<E>  
                          implements List<E>,RandomAccess,Cloneable,Serializable  

2.1.1 范例:设置内容
[java] view plaincopy

import java.util.ArrayList;  
import java.util.List;  
public class ArrayListDemo01 {  
    public static void main(String[] args) {  
        List<String> all = new ArrayList<String>(); // 实例化List接口  
        all.add("hello"); // 向集合中增加内容  
        all.add("world"); // 向集合中增加内容  
        all.add("!!!"); // 向集合中增加内容  
        for (int x = 0; x < all.size(); x++) {  
            System.out.println(all.get(x)) ;   
        }  
    }  
}  

说明:本例中使用List接口接收ArrayList实例,在取出数据的时候使用了List接口自己才有的get(int index)方法,如果使用Collection接收,取出数据时要先将其中的数据放到一个数组,然后从数组中取。如下例:
2.1.2 范例:Collection转换成数组输出
[java] view plaincopy

import java.util.ArrayList;  
import java.util.Collection;  
public class ArrayListDemo02 {  
    public static void main(String[] args) {  
        Collection<String> all = new ArrayList<String>(); // 实例化List接口  
        all.add("hello"); // 向集合中增加内容  
        all.add("world"); // 向集合中增加内容  
        all.add("!!!"); // 向集合中增加内容  
        all.remove("!!!"); // 从集合中删除指定对象  
        Object obj[] = all.toArray(); // 将所有的内容变为对象数组  
        for (int x = 0; x < obj.length; x++) {  
            String str = (String) obj[x];  
            System.out.print(str + "、");  
        }  
    }  
}  

说明:为了对输出数组的运行时类型进行更精确的控制,可以使用如下的方式来连接数组与集合。
2.1.3 范例:Collection转换成数组输出(精确控制数组类型)
[java] view plaincopy

import java.util.ArrayList;  
import java.util.Collection;  
public class ArrayListDemo02 {  
    public static void main(String[] args) {  
        Collection<String> all = new ArrayList<String>(); // 实例化List接口  
        all.add("hello"); // 向集合中增加内容  
        all.add("world"); // 向集合中增加内容  
        all.add("!!!"); // 向集合中增加内容  
        all.remove("!!!"); // 从集合中删除指定对象  
        Object obj[] = all.toArray(new String[]{}); // 将所有的内容变为对象数组  
                  //或者Object obj[] = alll.toArray(new String[0]);  
        for (int x = 0; x < obj.length; x++) {  
            String str = (String) obj[x];  
            System.out.print(str + "、");  
        }  
    }  
}  


3. 不允许重复的子接口:Set
List接口中的内容是允许重复的,但是如果现在要求集合中的内容不能重复的话,就只能使用Set接口。Set接口不像List那样对Collection进行了大量的扩充,它对外的方法视图与Collection是完全一样的。
3.1 散列存放的子类:HashSet
[java] view plaincopy

public class HashSet<E>  
extends AbstractSet<E>  
implements Set<E>, Cloneable, Serializable  

HashSet的定义方式和ArrayList很相似。
范例:添加元素与输出
[java] view plaincopy

import java.util.HashSet;  
import java.util.Set;  
public class HashSetDemo {  
    public static void main(String[] args) {  
        Set<String> all = new HashSet<String>();  
        all.add("hello");  
        all.add("hello"); // 重复设置  
        all.add("world");  
        all.add("!!!");  
        System.out.println(all) ;  
    }  
}  

说明:在Set接口中不允许有重复的元素存在,而且其中的元素是无序的,称为散列存放。
3.2 排序存放的子类:TreeSet
范例:排序存放
[java] view plaincopy

import java.util.Set;  
import java.util.TreeSet;  
public class TreeSetDemo {  
    public static void main(String[] args) {  
        Set<String> all = new TreeSet<String>();  
        all.add("B");  
        all.add("B");  
        all.add("X");  
        all.add("C");  
        all.add("A");  
        System.out.println(all);  
    }  
}  

说明:TreeSet不允许有重复内容,而且添加元素无序,输出时却是有序输出。
3.3 关于排序的补充
TreeSet中的元素对象可以排序要求它们实现Comparable接口,事先指定好排序规则。
范例:排序加入,compareTo()为0的对象元素将不会被再次添加
[java] view plaincopy

import java.util.Set;  
import java.util.TreeSet;  
class Person implements Comparable<Person> {  
    private String name;  
    private int age;  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    public String toString() {  
        return "姓名:" + this.name + ",年龄:" + this.age;  
    }  
    @Override  
    public int compareTo(Person o) {  
        if (this.age < o.age) {  
            return 1;  
        } else if (this.age > o.age) {  
            return -1;  
        } else {  
            return this.name.compareTo(o.name);   
        }  
    }  
}  
public class SortDemo {  
    public static void main(String[] args) {  
        Set<Person> all = new TreeSet<Person>();  
        all.add(new Person("张三", 20));  
        all.add(new Person("李四", 20));  
        all.add(new Person("李四", 20));  
        all.add(new Person("王五", 19));  
        System.out.println(all);  
    }  
}  

3.4 关于重复元素的补充
Comparable可以完成TreeSet类中重复元素的判断,如果这种判断重复的方式通用的话,那么在HashSet中应该也能够使用。但是测试的结果否定了这样的猜测,Set中去掉重复元素的操作不是靠Comparable完成,它们靠两个方法来确定,这两个方法在Object中提供了定义:
[java] view plaincopy

public boolean equals(Object obj);  
  
public int hashCode();  

hashCode()可以为对象提供一个标示编号,如果要对对象内容进行验证需要重写equals()方法。hashCode()返回一个数字,它是通过特定的算法得到的,指定算法并不难,指定一个好的使同一个hashCode尽可能少地对应对象就需要花些心思了。
范例:重写hashCode()和equals()
[java] view plaincopy

import java.util.HashSet;  
import java.util.Set;  
class Person{  
    private String name;  
    private int age;  
    public Person(String name, int age) {  
        this.name = name;  
        this.age = age;  
    }  
    @Override  
    public int 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) {  
        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;  
        } else if (!name.equals(other.name))  
            return false;  
        return true;  
    }  
    public String toString() {  
        return "姓名:" + this.name + ",年龄:" + this.age;  
    }  
}  
public class RepeatDemo {  
    public static void main(String[] args) {  
        Set<Person> all = new HashSet<Person>();  
        all.add(new Person("张三", 20));  
        all.add(new Person("李四", 20));  
        all.add(new Person("李四", 20));  
        all.add(new Person("王五", 19));  
        System.out.println(all);  
    }  
}  

说明:JVM在管理众多的对象时,其底层实现采用的是一个大的哈希表,这个哈希表可能是用数组来模拟的,数组的下标是hashCode,在哈希表上每个值对应的是一个链表,链表中有哈希值相同的对象的引用。这样进行对象查找时就可以如同查字典一样,先计算对象的hashCode,这时的hashCode如果一个索引;然后迅速定位到索引所对应的对象链表,然后借助equals的内容比较方式进行属性的逐一比对以找到对应的对象。
作者: 王琪    时间: 2013-12-18 17:18
这个问题,我也遇见过,就是在即合理比较对象的时候,不单要重写equals方法,还要重写hashcode等问题,我的这个资料不是一下就能解释清的,只是记得资料,对于系统的“集合里”对象比较,光覆写equals是不行的,我只查到说系统jvm分栈地址和堆地址?这个我也不明白,其实这个问题在我传的资料里还是没有说明,明白!!,大家有没有遇见过




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2