不包含重复元素的集合没有带索引的方法,所以不能使用普通for循环遍历是一个接口,不能直接实例化
package Java18.Set; //HashSet1.2 哈希值对集合的迭代次序不作任何保证 import java.util.HashSet; import java.util.Set; public class Setdemo { public static void main(String[] args) { Set set = new HashSet (); set.add("hello"); set.add("world"); set.add("java"); //不包含重复元素 set.add("world"); //遍历 for(String s : set){ System.out.println(s); } }
哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值
public int hashCode():返回对象的哈希码值
对象的哈希值特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同。
package Java18.Set;
public class hashdemo {
public static void main(String[] args) {
//创建学生对象
Student s = new Student("lyy",24);
//同一个对象多次调用hashCode()方法返回的哈希值相同
System.out.println(s.hashCode());//356573597
System.out.println(s.hashCode());
//默认情况下不同对象的哈希值是不一样的
//通过方法重写可以实现不同对象的哈希值是相同的
Student s2 = new Student("lyy",24);
System.out.println(s2.hashCode());//1735600054
System.out.println("----------");
System.out.println("hello".hashCode());//99162322
System.out.println("world".hashCode());//113318802
System.out.println("world".hashCode());//113318802
System.out.println("-------------------------");
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
}
}
1.3 HashSet集合概述和特点
HashSet集合特点
底层数据结构为哈希表对集合的迭代次序不作任何保证,也就是说不保证存储和取出的元素顺序一致没有带索引的方法,不能使用普通for循环遍历由于是Set集合,所以是不包含重复元素的集合
package Java18.Set;
import java.util.HashSet;
import java.util.Iterator;
public class demo2 {
public static void main(String[] args) {
HashSet hash = new HashSet();
hash.add("l");
hash.add("w");
hash.add("d");
hash.add("q");
//遍历
Iterator it = hash.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("------------");
for (String s : hash){
System.out.println(s);
}
}
}
1.3 HashSet集合保证元素唯一性源码分析
HashSet1.4 HashSet 集合存储学生对象并遍历hash = new HashSet (); hash.add("l"); hash.add("w"); hash.add("d"); hash.add("q"); ----------------------------------------------- //调用add方法将元素存储进hashSet,add方法中调用put方法,其中e为传入的元素 public boolean add(E e) { return map.put(e, PRESENT)==null; } //元素参数对于key,其中hash(key)表示元素的哈希值,然后在put方法中调用putVal方法 public V put(K key, V value) { return putVal(hash(key), key, value, false, true); } //利用hashCode()方法获取key的哈希值 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } //hash和元素的hashCode()方法相关 final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node [] tab; Node p; int n, i; //如果哈希表未初始化,就对其进行初始化 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; //根据对象的hash值计算对象的存储位置,如果该位置没有元素就存储元素 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); else { Node e; K k; if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) e = p; else if (p instanceof TreeNode) e = ((TreeNode )p).putTreeval(this, tab, hash, key, value); else { for (int binCount = 0; ; ++binCount) { if ((e = p.next) == null) { p.next = newNode(hash, key, value, null); if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st treeifyBin(tab, hash); break; } if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; p = e; } } if (e != null) { // existing mapping for key V oldValue = e.value; if (!onlyIfAbsent || oldValue == null) e.value = value; afterNodeAccess(e); return oldValue; } } ++modCount; if (++size > threshold) resize(); afterNodeInsertion(evict); return null; }
学生类,在该类中重写hashCode和equal方法,使得成员变量相同的学生认为是同一个变量
package Java18.Set;
public class Student {
private String name;
private int age;
public Student(){
}
public Student(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
//重写hashCode和equal方法
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
if (age != student.age) return false;
return name != null ? name.equals(student.name) : student.name == null;
}
@Override
public int hashCode() {
int result = name != null ? name.hashCode() : 0;
result = 31 * result + age;
return result;
}
}
package Java18.Set;
import java.util.HashSet;
import java.util.Iterator;
public class HashsetDemo {
public static void main(String[] args) {
HashSet ha = new HashSet();
//创建学生对象
Student s1 = new Student("lyy",23);
Student s2 = new Student("lyq",24);
Student s3 = new Student("sss",43);
Student s4 = new Student("lyy",23);
//集合中添加元素
ha.add(s1);
ha.add(s2);
ha.add(s3);
ha.add(s4);
//遍历
Iterator it = ha.iterator();
while(it.hasNext()){
Student s = it.next();
System.out.println(s.getName()+","+s.getAge());
}
System.out.println("---------------");
for(Student s : ha){
System.out.println(s.getName()+","+s.getAge());
}
}
}
1.5 linkedHashSet 集合概述和特点
哈希表和链表实现了Set接口,具有可预测的迭代次序。由链表保证元素有序,也就是说元素的存储和取出顺序是一致的由哈希表保证元素唯一,也就是说没有重复的元素
这种实现不同于HashSet,它维持于所有条目的运行双向链表。
练习:存储字符串并遍历
package Java18.Set;
import java.util.Iterator;
import java.util.linkedHashSet;
public class linkedHashSetdemo {
public static void main(String[] args) {
linkedHashSet lhs = new linkedHashSet();
//添加元素
lhs.add("lll");
lhs.add("yyy");
lhs.add("qqq");
lhs.add("yyy");
//遍历
//实现set接口 可以调用Iterator迭代器
Iterator it = lhs.iterator();
while(it.hasNext()){
String s = it.next();
System.out.println(s);
}
System.out.println("---------------");
//增强for
for(String s : lhs){
System.out.println(s);
}
}
}
1.6 TreeSet 集合概述和特点
TreeSet 集合的特点
元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体的排序方式取决于构造方法
TreeSet ():根据元素的自然顺序进行排序
TreeSet (Comparator , comparator):根据指定的比较器进行排序没有索引的方法,不能使用普通for循环遍历,可以使用增强for和迭代器进行遍历
联系:存储整数并遍历
package Java18.Set;
import java.util.Iterator;
import java.util.TreeSet;
public class TreeSetdemo {
public static void main(String[] args) {
TreeSet Tr = new TreeSet();
//集合添加元素
Tr.add(1);
Tr.add(2);
Tr.add(3);
Tr.add(7);
Tr.add(5);
//遍历
//迭代器Iterator方法
Iterator it = Tr.iterator();
while(it.hasNext()){
int i = it.next();
System.out.println(i);
}
System.out.println("---------------");
//增强for
for(int i : Tr){
System.out.println(i);
}
}
}
输出结果会按照整数数据进行排序输出
存储学生对象并遍历,创建TreeSet 集合使用无参构造方法要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
学生类及CompareTo方法的重写
package Java18.Set.Treeset; public class Student implements Comparable{ private int age; private String name; public Student(){ } public Student(String name,int age){ this.name = name; this.age = age; } public void setName(String name){ this.name = name; } public void setAge(int age){ this.age = age; } public String getName(){ return name; } public int getAge(){ return age; } //重写Comparable里面的方法 @Override public int compareTo(Student s) { // return 0; // return 1; // return -1; //按照年龄从小到大排序 int num = this.age - s.age; //年龄相同时,按照姓名的字母排序 int num2 = num==0?this.name.compareTo(s.name):num; return num2; } }
学生类调用及排序
package Java18.Set.Treeset;
import java.util.TreeSet;
public class Treesetdemo2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet();
//创建学生对象
Student s1 = new Student("lll",22);
Student s2 = new Student("sss",23);
Student s3 = new Student("eee",22);
Student s4 = new Student("qqq",19);
//添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
//遍历
for(Student s : ts){
System.out.println(s.getName()+","+s.getAge());
}
}
}
1.7 比较器Comparatot的使用
存储学生对象并遍历,创建TreeSet 集合使用无参构造方法要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
学生类
package Java18.Set.TreeSet2;
public class Student {
private String name;
private int age;
public Student(){
}
public Student(String name, int age){
this.name = name;
this.age = age;
}
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
测试类
package Java18.Set.TreeSet2;
import java.util.Comparator;
import java.util.TreeSet;
public class Treesetdemo1 {
public static void main(String[] args) {
//创建集合对象
TreeSet ts = new TreeSet(new Comparator() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge();
int num2 = num==0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
});
//创建学生对象
Student s1 = new Student("lll", 22);
Student s2 = new Student("sss", 23);
Student s3 = new Student("eee", 22);
Student s4 = new Student("qqq", 19);
//添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
//遍历
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写Comparator(To 1 ,T o2)方法 1.8 案例:学生成绩排序
两种方法:
自然排序Comparable的使用,学生类中重写CompareTo方法
package Java18.Set.Treeset3; public class Student implements Comparable{ private String name; private int ma; private int ch; public Student(){ } public Student(String name,int ma,int ch){ this.name = name; this.ma = ma; this.ch = ch; } public void setName(String name){ this.name = name; } public void setMa(int ma){ this.ma = ma; } public void setCh(int ch){ this.ch = ch; } public String getName(){ return name; } public int getMa(){ return ma; } public int getCh(){ return ch; } @Override public int compareTo(Student s) { //先按总成绩排序 int num = s.ma+s.ch-this.ma-this.ch; //若成绩相同,先比较语文成绩,若相同则按名字排序 int num2 = num==0?s.ch-this.ch:num; int num3 = num2 == 0?s.name.compareTo(this.name):num2; return num3; } }
package Java18.Set.Treeset3;
import java.util.TreeSet;
public class demo {
public static void main(String[] args) {
//创建集合
TreeSet ts = new TreeSet();
//创建学生对象
Student s1 = new Student("lyy",93,96);
Student s2 = new Student("lyq",95,97);
Student s3 = new Student("dqd",90,93);
Student s4 = new Student("hsy",85,91);
Student s5 = new Student("dst",91,85);
//集合添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历并按成绩排序成绩相同则按姓名
for(Student s : ts){
System.out.println(s.getName()+","+s.getCh()+","+s.getMa());
}
}
}
比较器Comparatot的使用
学生类
package Java18.Set.Treeset3;
//比较器的使用
public class Student2 {
private String name;
private int ma;
private int ch;
public Student2(){
}
public Student2(String name, int ma, int ch) {
this.name = name;
this.ma = ma;
this.ch = ch;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMa() {
return ma;
}
public void setMa(int ma) {
this.ma = ma;
}
public int getCh() {
return ch;
}
public void setCh(int ch) {
this.ch = ch;
}
//定义一个求总分的方法
public int getSum(){
return this.ch+this.ma;
}
}
测试类,使用局部内部类重写compare方法
package Java18.Set.Treeset3;
//比较器的使用
import java.util.Comparator;
import java.util.TreeSet;
public class demo2 {
public static void main(String[] args) {
//创建集合对象,调用局部内部类
TreeSet ts = new TreeSet(new Comparator() {
@Override
public int compare(Student2 s1, Student2 s2) {
//比较总分
// int num = s2.getCh()+s2.getMa()-s1.getCh()-s1.getMa();
int num = s2.getSum()-s1.getSum();
//若总分相同,比较语文成绩,语文成绩相同比较名字进行排序
int num2 = num==0?s1.getCh()-s2.getCh():num;
int num3 = num2==0?s1.getName().compareTo(s2.getName()):num;
return num3;
}
});
//创建学生对象
Student2 s1 = new Student2("lyy",93,96);
Student2 s2 = new Student2("lyq",95,97);
Student2 s3 = new Student2("dqd",90,93);
Student2 s4 = new Student2("hsy",85,91);
Student2 s5 = new Student2("dst",91,85);
//集合添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
//遍历并按成绩排序成绩相同则按姓名
for(Student2 s : ts){
System.out.println(s.getName()+","+s.getCh()+","+s.getMa()+","+s.getSum());
}
}
}
//获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出
package Java18.Set.TreeSet4;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class demo {
public static void main(String[] args) {
//创建对象
Set s = new HashSet();
//创建随机数对象
Random r = new Random();
while(s.size()<=10){
//产生一个随机数添加到集合
int number = r.nextInt(20)+1;
s.add(number);
}
for(Integer i:s){
System.out.println(i);
}
}
}



