哈希表是一种数据结构,能够快速定位已存储的数据的地址:
1.通过hashCode()计算哈希码,通过该哈希码定位到内存地址。hash码的计算通常基于对象的某些特有属性进行计算;
2.如果地址不同,则直接存入;
3.如果地址相同,则调用该对象的equals()比较内容;如果内容相同,则丢弃,不同,则顺延一个空间,存入。
HashSet HashMap 都是基于hash表的数据结构进行实现的。
HashSet确保对象唯一,通过hashCode()与equals()来完成
hashCode() 计算不同对象的哈希码
equals() 当地址相同时,判断对象是否相同,如果相同,则丢弃,如果不同,就顺延存入。这样便确保了对象的唯一性
public class Person {private String name;private int age;public Person() {super();}public Person(String name, int age) {super();this.name = name;this.age = age;}public Person(String name) {super();this.name = name;}/*** Person对象的哈希值计算方法*/@Overridepublic int hashCode() {return name.hashCode()+age*31;}/*** 比较Person对象是否相同的规则*/@Overridepublic boolean equals(Object obj) {Person p = (Person)obj;return this.name.equals(p.getName()) && this.age == p.getAge();}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
public static void main(String[] args) {Set<Person> set = new HashSet<Person>();set.add(new Person("zs1",10));set.add(new Person("zs2",20));set.add(new Person("zs3",30));set.add(new Person("zs1",10));//hachCode()结果相同,equals()结果为true,该对象被丢弃Iterator<Person> iter = set.iterator();while(iter.hasNext()) {Person p = iter.next();System.out.println(p.getName()+"--"+p.getAge());}}
TreeSet确保对象唯一,并且按指定规则排序,通过compare()或compareTo()实现
TreeSet中比较器,返回int值,如果为0,表示相同,则不存,确保唯一。
TreeSet的实现,不依赖hashCode()和equals()。
如,String字符串类实现了Comparable接口,复写了compareTo()
public int compareTo(String anotherString) {int len1 = value.length;int len2 = anotherString.value.length;int lim = Math.min(len1, len2);char v1[] = value;char v2[] = anotherString.value;int k = 0;while (k < lim) {char c1 = v1[k];char c2 = v2[k];if (c1 != c2) {return c1 - c2; //比较字符的自然顺序}k++;}return len1 - len2;}
1. 自定义比较器,实现Comparator接口;在存入TreeSet集合的时候指定比较器。
让集合具备比较功能,而且将覆盖元素自身的比较规则!
应用场景:
a.覆盖对象本身具备的比较规则,如String类默认按自然顺序排序,将其覆盖为按长度排序
b.为其它类(非自己创建的类)指定比较规则,将比较功能传入集合中,让集合具备比较功能
public class Person {private String name;private int age;public Person() {super();}public Person(String name, int age) {super();this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
import java.util.Comparator;public class PersonComparator implements Comparator<Person> {/*** 姓名不同* 存入,并按姓名排序* 姓名相同,比较年龄* 年龄不同,则首先按姓名,再按年龄排序* 年龄也相同,则为同一个对象,不存!*/@Overridepublic int compare(Person o1, Person o2) {//1.按姓名比较int comp = o1.getName().compareTo(o2.getName());//2.姓名相同,则继续按年龄比较,如果年龄相同,则表示同一个对象,不存!return comp==0?(o1.getAge()-o2.getAge()):comp;}}
public static void main(String[] args) {Set<Person> set = new TreeSet<Person>(new PersonComparator());//传入比较器set.add(new Person("zs1",10));set.add(new Person("zs2",20));set.add(new Person("zs2",15));//姓名相同的情况下,则年龄作为次要排序条件set.add(new Person("zs1",10));//哈希值相同,equals()结果为true,该对象被丢弃Iterator<Person> iter = set.iterator();while(iter.hasNext()) {Person p = iter.next();System.out.println(p.getName()+"--"+p.getAge());}}
结果:
zs1--10
zs2--15
zs2--20
2. 实现Comparable接口
public class Person implements Comparable<Person>{private String name;private int age;public Person() {super();}public Person(String name, int age) {super();this.name = name;this.age = age;}/*** 排序规则:* 首先按姓名排* 姓名相同,再按年龄排* 年龄也相同,则为同一个对象,不存!*/@Overridepublic int compareTo(Person o) {int temp = this.name.compareTo(o.getName());return temp==0 ? (this.age-o.getAge()) : temp;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}}
public static void main(String[] args) {Set<Person> set = new TreeSet<Person>();set.add(new Person("zs1",10));set.add(new Person("zs2",20));set.add(new Person("zs2",15));//姓名相同的情况下,再按年龄排序set.add(new Person("zs1",10));//哈希值相同,equals()结果为true,该对象被丢弃Iterator<Person> iter = set.iterator();while(iter.hasNext()) {Person p = iter.next();System.out.println(p.getName()+"--"+p.getAge());}}
结果: