关于java:Set集合-笔记

11次阅读

共计 6019 个字符,预计需要花费 16 分钟才能阅读完成。

Set 汇合

不蕴含反复元素;没有带索引的办法,所以不能应用一般 for 循环遍历
set 是一个接口不能间接实例化,得找它的实现类

set 汇合存储字符串并遍历

HashSet:对汇合的迭代程序不做任何保障

Set<String> set = new HashSet<String>();// 创立汇合对象
// 增加元素
set.add("Hello");
set.add("World");
set.add("java");
// 增加元素 不蕴含反复元素的汇合
set.add("World");
// 遍历 加强 for 循环
for(String s : set){sout(s);
}

输入程序不一样,就是因为 HashSet 不能保障迭代程序

哈希值

是 JDK 依据对象的 地址 或者 字符串 或者数字算进去的 int 类型的 数值
Object 类种有一个办法能够获取 对象的哈希值

Student s1 = new Student(name:"林青霞",age:30);// 创立一个学生对象
// 通过对象调用 hashCode 办法失去哈希值
sout(s1.hashCode());
sout(s1.hashCode());

Student s2 = new Student(name:"林青霞",age:30);// 创立一个学生对象
sout(s2.hashCode());

同一个对象屡次调用 hashCode()办法返回的哈希值是雷同的

即使成员变量是雷同的,然而因为对象不同所以默认状况下哈希值也是不同的,因为如果重写 hashCode 办法,返回默认值变成一样的,那输入的就是一样的了



通过办法重写,能够实现不同对象的哈希值是雷同的
不同对象的哈希值不同,雷同对象的哈希值雷同

这两个对象的哈希值雷同是因为字符串重写了 object 的 hashCode 办法

HashSet 汇合概述和特点

在 util 包下

HashSet<String> hs = new HashSet<String>();// 创立汇合对象
// 增加元素, 没有索引
hs.add("Hello");
hs.add("World");
hs.add("java");
// 遍历 加强 for 循环
for(String s : hs){sout(s);
}

HashSet 汇合保障元素唯一性源码剖析


常见数据结构之哈希表


HashSet 汇合无参构造方法默认汇合初始长度是 16,而后对数据的哈希值对 16 取余,余数是多少就寄存在哪个地位,首先 hello 先寄存在 2 地位,而后发现 world 也须要寄存在 2 地位,而后两者的哈希值不一样,所以造成链表,而后 java 要和 2 地位的两个元素别离比拟哈希值发现不同,造成链表;前面那个 world 也是 2 地位,须要和后面三个进行比拟,发现和第一个哈希值不同,而后和第二个比发现和后面的 world 哈希值雷同,而后及比拟内容,发现内容也雷同,从而断定为先雷同元素,不进行存储
通话元素寄存在 3 地位,而后对重地元素进行剖析,发现也须要放在 3 地位,3 地位有元素,所以须要和通话元素进行哈希值比拟,发现哈希值雷同,当哈希值雷同时就须要对内容荣进行比拟,而后对他们的内容进行比照,发现内容不雷同,所以重地元素也能够存储进来造成链表




案例 HashSet 汇合存储学生并遍历

HashSet<Student> hs = new HashSet<Student>();// 创立 HashSet 汇合对象
Student s1 = new Student(name:"林青霞",age:30);// 创立一个学生对象
Student s2 = new Student(name:"张曼玉",age:35);// 创立一个学生对象
Student s3 = new Student(name:"王祖贤",age:33);// 创立一个学生对象
//s3 和 s4 成员变量值雷同,依照要求就认为是同一个对象,所以 s4 就应该存储不进去
Student s4 = new Student(name:"王祖贤",age:33);// 创立一个学生对象
// 把学生增加到汇合
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
// 遍历 加强 for 循环
for(Student s : hs){sout(s.getName() + "," + s.getAge());

然而依照下面的的代码 s4 是增加胜利的了,所以须要进行批改能力保障元素的唯一性

所以 Student 类须要重写 HashCode 办法和 equals 办法,而后就保障唯一性了

LinkedHashSet 汇合概述和特点

是由哈希表和链表实现的 Set 接口,具备可预测的迭代程序
由链表保障元素有序,也就是说元素的存储和去除程序是统一的

LinkedHashSet 存储字符串并遍历
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();// 创立汇合对象
// 增加元素
linkedHashSet.add("Hello");
linkedHashSet.add("World");
linkedHashSet.add("java");
// 增加元素 不蕴含反复元素的汇合
linkedHashSet.add("World");
// 遍历 加强 for 循环
for(String s : linkedHashSet){sout(s);
}

TreeSet 汇合概述和特点

间接的实现了 Set 接口

TreeSet 存储整数并遍历

汇合里存储的是援用类型,所以存储整数应该用她的包装类 Interger

TreeSet<Interger> ts = new TreeSet<Interger>();// 创立汇合对象
// 增加元素 主动装箱
ts.add(10);
ts.add(40);
ts.add(30);
ts.add(50);
ts.add(20);
// 增加元素 不蕴含反复元素的汇合
ts.add(30);
// 调用的是无参结构 所以是天然排序,是从小到大
// 遍历 加强 for 循环
for(Interger i : ts){sout(i);
}

天然排序 Comparable 的应用

TreeSet<Student> ts = new TreeSet<Student>();// 创立 HashSet 汇合对象
Student s1 = new Student(name:"xishi",age:29);// 创立一个学生对象
Student s2 = new Student(name:"wangzhaojun",age:28);// 创立一个学生对象
Student s3 = new Student(name:"diaochan",age:30);// 创立一个学生对象
Student s4 = new Student(name:"yangyuhuan",age:33);// 创立一个学生对象
//s4 和 s5 成员年龄雷同
Student s5 = new Student(name:"linqingxia",age:33);// 创立一个学生对象
// 把学生增加到汇合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
// 遍历 加强 for 循环
for(Student s : ts){sout(s.getName() + "," + s.getAge());

出现异常

是因为如果要做天然排序就得让类实现该接口,因为该接口能够对类的对象进行排序,所以须要让学生类实现 Comparable 这个接口,而后重写这个接口外面的办法 compareTo


因为重写的 compareTo 办法 返回的是 0 ,所以在增加第二个 第三个 第四个元素的时候就会 认为和第一个是同一个元素,所以增加不上 ,返回值是 0,阐明元素是相等的,反复的就不会存储。
改成 return 1; 阐明 s2 比 s1 大,s3 比 s2 大,s4 比 s3 大,就能够增加,而后依照从小到大的程序输入,也就是正序


改成 return -1; 阐明 s2 比 s1 小,s3 比 s2 小,s4 比 s3 小,就能够增加,而后依照从小到大的程序输入,也就是倒序


返回是 0,就认为是反复的相等的不增加;返回是正数,就认为是前面的小,也就是顺叙存储;返回是负数,就认为是前面的大,也就是升序存储

题目要求依照年龄从小到大排序,依照姓名的字母程序排序

也就是说要改良重写的 compareTo 办法的返回值
办法外部其实自身就有这个属性,拿 s1 s2 举例来看,s1 不须要和他人比,s2 须要和 s1 比,这个 this 就是 s2,这个 s 就是 s1

用前面的 age 减去后面的,返回差值,就是 升序 ,也就就是从小到大;用后面的 age 减去前面的,返回差值,就是 降序 ,也就是从大到小

当年龄一样的时候返回 0,就存储不进来,然而依照题目要求要用名字首字母排序,所以进行更改

字符串自身能够自行排序

TreeSet<Student> ts = new TreeSet<Student>();// 创立 HashSet 汇合对象
Student s1 = new Student(name:"xishi",age:29);// 创立一个学生对象
Student s2 = new Student(name:"wangzhaojun",age:28);// 创立一个学生对象
Student s3 = new Student(name:"diaochan",age:30);// 创立一个学生对象
Student s4 = new Student(name:"yangyuhuan",age:33);// 创立一个学生对象
//s4 和 s5 成员年龄雷同
Student s5 = new Student(name:"linqingxia",age:33);// 创立一个学生对象
//s6 和 s5 成员姓名年龄都雷同
Student s6 = new Student(name:"linqingxia",age:33);// 创立一个学生对象
// 把学生增加到汇合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
// 遍历 加强 for 循环
for(Student s : ts){sout(s.getName() + "," + s.getAge());

int num = this.age - s.age;
int num1 = num == 0?this.name.compareTo(s.name):num
// 当年龄雷同的时候就返回 this.name.compareTo(s.name),当年龄不同的时候就返回 num
renturn num1;


天然排序 Comparator 的应用


带参结构,也就是指定比拟器的形式,依照年龄从小到大排序
传递了一个比拟器接口

// 创立 HashSet 汇合对象匿名外部类形式 上面会主动重写 conpare 办法
TreeSet<Student> ts = new TreeSet<Student>(**new Comparator<Student>({
     @Override
     public int compare(Student s1,Student s2){
       // 这个办法外部的 this 代表的是 TreeSet 而不是学生,所以办法的参数传了两个学生对象
       // 年龄从小到大排序
       //this.age - s.age
       //**s1 是 this s2 是 s **
       int num = s1.getAge()-s2.getAge();// 在这里不能拜访学生类的公有成员
       int num1 = num == 0?s1.getName().compareTo(s2.getName()):num
       return num1;
     }
}**);
Student s1 = new Student(name:"xishi",age:29);// 创立一个学生对象
Student s2 = new Student(name:"wangzhaojun",age:28);// 创立一个学生对象
Student s3 = new Student(name:"diaochan",age:30);// 创立一个学生对象
Student s4 = new Student(name:"yangyuhuan",age:33);// 创立一个学生对象
//s4 和 s5 成员年龄雷同
Student s5 = new Student(name:"linqingxia",age:33);// 创立一个学生对象
//s6 和 s5 成员姓名年龄都雷同
Student s6 = new Student(name:"linqingxia",age:33);// 创立一个学生对象
// 把学生增加到汇合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
// 遍历 加强 for 循环
for(Student s : ts){sout(s.getName() + "," + s.getAge());

Set 案例 问题排序


通过比拟器进行排序实现
s1 呈现在后面是从低到高,s2 呈现在后面是从高到低


总分雷同依照语文问题升序进行

当总分和单科分数都一样时,依照名字从小到大排序


@Override
            public int compare(Student s1, Student s2) {
                // 升序
                return s1.getAge()-s2.getAge();
                return s1.getAge().compareTo(s2.getAge());
                // 降序
                return s2.getAge()-s1.getAge();
                return s2.getAge().compareTo(s1.getAge());

参考网址 comparable 和 comparator 的区别
http://www.manongjc.com/artic…
Comparator 和 Comparable 的区别

    Comparable: 本人 (this) 和他人 (参数) 比拟, 本人须要实现 Comparable 接口, 重写比拟的规定 compareTo 办法
    Comparator: 相当于找一个第三方的裁判, 比拟两个
    Comparator 的排序规定:
    o1-o2: 升序
    Comparable 接口的排序规定:
    被排序的汇合里边存储的元素, 必须实现 Comparable, 重写接口中的办法 compareTo 定义排序的规定
    public class Person implements Comparable<Person>{本人(this)- 参数: 升序

Set 案例 不反复的随机数

// 创立 HashSet 汇合对象
Set<Integer> set = new HashSet<Integer>();
// 创立随机数对象
Random r = new Random();
// 判断汇合的长度是不是小于 10
while(set.size()<10){
    // 产生一个随机数增加到汇合 1 -20 之间
    int number = r.nextInt(bound:20)+1;
    set.add(number);// 有反复的无奈增加进去
// 遍历 加强 for 循环
for(Integer i : set){sout(i);    
}


改成 TreeSet 汇合

// 创立 TreeSet 汇合对象
Set<Integer> set = new TreeSet<Integer>();

会进行从小到大的排序

正文完
 0