Set:唯一
--HashSet:无序,唯一
----LinkedHashSet:采用的存储为哈希表+链表的结构(java.util.LinkedHashSet实现了Set接口,继承HashSet)
--TreeSet:唯一,有序(大小顺序)
Set接口继承Collection接口,没有额外添加方法
特点:唯一(不重复),无序(位置顺序),无法通过下标索引获取元素
其下有三个常用的实现类
HashSet***
常用的构造函数
HashSet():构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
HashSet(int initialCapacity):构造一个新的空 set,其底层 HashMap 实例具有指定的初始容量和默认的加载因子(0.75)
常用的函数:
add(E e):如果此 set 中尚未包含指定元素,则添加指定元素。
size():获取容器中元素的个数
iterator():返回对此 set 中元素进行迭代的迭代器。
isEmpty():如果此 set 不包含任何元素,则返回 true。
contains(Object o) :如果此 set 包含指定元素,则返回 true。
remove(Object o):如果指定元素存在于此 set 中,则将其移除。
遍历方式:
1.使用for-each遍历
2.使用迭代器进行遍历
TreeSet*
LinkedHashSet
public class TestHashSet { public static void main(String[] args) { Set<String> set = new HashSet<String>(); System.out.println("容器是否为空:"+set.isEmpty()); set.add("java"); set.add("oracle"); set.add("html"); set.add("java"); System.out.println("元素的个数:"+set.size()); System.out.println("容器是否为空:"+set.isEmpty()); System.out.println("是否包含java:"+set.contains("java")); //1.使用for-each进行遍历 for (String string : set) { System.out.println(string); } System.out.println("------"); //2.使用迭代器进行遍历 Iterator<String> iter = set.iterator(); while(iter.hasNext()){ String str = iter.next(); System.out.println(str); } } }
HashSet存储结构采用hashtable(哈希表+链表结构进行存储)
优点:
查询(哈希算法),添加,删除速(链表)度快
hashcode(哈希码):同哈希码计算对象的存储位置 y=k(x)
y:代表存储位置 x:哈希码
缺点:无序(位置顺序),无法通过下标访问--->get(i)
添加情况:添加时会计算存储位置--->获取哈希码--->通过调用hashcode()获取哈希码
情况1:一次添加成功
情况2:多次添加,存在重复,去掉重复项--->通过 equals()内容是否一致
情况3:在相同位置,多次添加成功
hashcode()与equals()的关系
1。hashcode相同,equals()是不一定相同
2.equals()比较两个对象内容相同(值为true),hashcode值是一定相同
注意:
hashSet中去掉重复项会调用hashCode()和equals()
需要重写Object类中hashCode()和equals()
1.先调用hashCode()获取对象的hash码,如果hash码不相同,对象肯定不同,不再调用equals方法进行比较
提高了效率:
传统做法:如果要比较1000的对象,需要调用1000次的equals()方法
使用hash码:先比较hash是否相同,如果hash码相同才调用equals进行比较
2.通过hash码计算存储位置: y=k(x)
hashCode如何计算:
1.Integer类型:用自身数值做hashcode
2.Student
package cn.zzsxt.set1; public class Student { private String name; private int age; public Student(){ } public Student(String name,int age){ 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; } @Override public String toString() { return "姓名:"+name+",年龄:"+age; } @Override public int hashCode() { System.out.println("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) { System.out.println("equals方法被调用了...."); if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) 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 class TestHashSet2 { public static void main(String[] args) { Set<Student> set = new HashSet<Student>(); Student stu1 = new Student("zhangsan",20); Student stu2 = new Student("zhangsan2",22); Student stu3 = new Student("zhangsan3",23); Student stu4 = new Student("zhangsan2",22);//?? Student stu5 = new Student("zhangsan2",22);//?? // set.add("java"); //一旦使用泛型,该容器只能保存指定的数据类型 set.add(stu1); set.add(stu2); set.add(stu3); set.add(stu4); set.add(stu5); System.out.println(set.size()); for (Student student : set) { System.out.println(student);//System.out.println(student.toString()); } } }
Set:唯一
--HashSet:无序,唯一
----LinkedHashSet:采用的存储为哈希表+链表的结构
--TreeSet:唯一,有序(大小顺序)
java.util.LinkedHashSet实现了Set接口,继承HashSet
特点:唯一,有序(位置顺序)
常用的构造函数
LinkedHashSet():构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set。
LinkedHashSet(int initialCapacity):构造一个带指定初始容量和默认加载因子 (0.75) 的新空链接哈希 set。
常用方法:
add(E e):添加
remove(E e):移除指定元素
size():查看容器元素的个数
contains(E e):是否包含指定元素
iterator():返回一个迭代器
public class TestLinkedHashSet { public static void main(String[] args) { LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>(); linkedHashSet.add("java"); linkedHashSet.add("oracle"); linkedHashSet.add("html"); linkedHashSet.add("html"); linkedHashSet.remove("java");// System.out.println("元素个数:"+linkedHashSet.size()); System.out.println("是否包含java:"+linkedHashSet.contains("java")); //采用遍历:for-each for (String string : linkedHashSet) { System.out.println(string); } System.out.println("--------------------------"); //采用迭代器:Iterator for(Iterator<String> iter = linkedHashSet.iterator();iter.hasNext();){ String str = iter.next(); System.out.println(str); } } }
TreeSet:采用二叉树进行存储,实现类Set接口
特点:唯一,有序(自然顺序)
优点:
查找效率比List要高,但没有HashSet高
构造函数:
TreeSet():构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。
public class TestTreeSet { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<String>(); treeSet.add("java"); treeSet.add("oracle"); treeSet.add("html"); treeSet.add("aa"); treeSet.add("ab"); // treeSet.add("html"); System.out.println("元素个数:"+treeSet.size()); //使用for-each遍历 for (String string : treeSet) { System.out.println(string); } } }
TreeSet存储对象的方法:
package cn.zzsxt.set2; public class Student implements Comparable<Student>{ private String name; private int age; private int score; public Student() { } public Student(String name, int age, int score) { this.name = name; this.age = age; this.score = score; } 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 int getScore() { return score; } public void setScore(int score) { this.score = score; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); result = prime * result + score; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; Student other = (Student) obj; if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; if (score != other.score) return false; return true; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + ", score=" + score + "]"; } /** * 重写Compareable接口中的方法 * 完成比较业务逻辑 * 按照分数为第一顺序倒序 * 年龄为第二顺序进行倒序存放 * */ @Override public int compareTo(Student o) { if(this.score>o.score){ return -1; }else if(this.score==o.score){ if(this.age>o.age){ return -1; }else if(this.age==o.age){ return 0; }else{ return 1; } }else { return 1; } } }
出现异常:java.lang.ClassCastException
导致原因:TreeSet采用的二叉树进行存放(对要保存的元素要求有大小顺序,如果要比较对象大小必须实现Compareable接口,重写compareTo方法)
需求:
按照分数为第一顺序,年龄为第二顺序进行存放
public class TestTreeSet { public static void main(String[] args) { TreeSet<Student> treeSet = new TreeSet<Student>(); Student stu1 = new Student("zhangsan",20,80); Student stu2 = new Student("lisi",21,82); Student stu3 = new Student("wangwu",22,80); Student stu4 = new Student("wangwu",22,80); treeSet.add(stu1); treeSet.add(stu2); treeSet.add(stu3); treeSet.add(stu4); for (Student student : treeSet) { System.out.println(student);//调用student中的toString()方法 } } }
构造函数:
TreeSet()构造一个新的空 set,该 set 根据其元素的自然顺序进行排序(本质上调用对象中重写Comparable接口中compareTo方法)。
构造一个新的空 TreeSet,它根据指定比较器进行排序
TreeSet(Comparator<? super E> comparator)
构造一个新的空 TreeSet,它根据指定比较器进行排序。
java.util.Comparator:比较器接口,可能更加灵活的完成对象的比较
package cn.zzsxt.set2; import java.util.Comparator; public class LengthCom implements Comparator<Student> { /** * 比较用来排序的两个参数。 * 根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数 */ @Override public int compare(Student o1, Student o2) { int len1 = o1.getName().length(); int len2 = o2.getName().length(); if(len1>len2){ return 1; }else if(len1==len2){ return 0; }else{ return -1; } } }
public class TestTreeSet2 { public static void main(String[] args) { //创建一个比较器 LengthCom lencom = new LengthCom(); //它根据指定比较器进行排序 TreeSet<Student> treeSet = new TreeSet<Student>(lencom); Student stu1 = new Student("zhangsan",20,80); Student stu2 = new Student("lisi",21,82); Student stu3 = new Student("wangwu",22,80); treeSet.add(stu1); treeSet.add(stu2); treeSet.add(stu3); for (Student student : treeSet) { System.out.println(student);//调用student中的toString()方法 } } }
需求:
按照姓名的长度进行排序