黑马程序员——JAVA基础------集合框架(二)----Set接口

时间:2021-08-26 11:29:40

——Java培训、Android培训、iOS培训、.Net培训、期待与您交流! ——

一、Set接口

1 、 Set 接口

public interface Set<E> extends Collection<E>

一 个 不 包 含 重 复 元 素 的 collection 。更 确 切 地 讲 , set 不 包 含 满 足 el.equaIs(e2) 的 元 素 。对 el 和 e2, 并 且 最 多 包 含 一 个 null 元 素 。 正 如 其 名 称 所 暗 示 的 , 此 接 口 模 仿 了 数 学
上 的set 抽 象 。

2、HashSet 接口

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

类实现Set接口,由哈希表支持。它是无序的,不允许元素的重复,允许使用null 元素。初始容量为16,加载因子为0.75

HashSet是如何保证元素唯一性呢?
是通过元素的两个方法,hashCode 和 equals来完成
如果元素的hashCode值相同,才会判断equals是否为true
如果元素的hashCode值不同,不会调用equals

注意:对于判断元素是否存在,以及删除等操作,依赖来的方法是元素的hashcode和equals方法

代码演示:

package com.joe.list;

import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;

/**
* HashSet实现类: 1、不保证迭代顺序 2、底层使用HashMap实现(哈希表)
* 3、自定义对象是否重复的判断条件是:先判断hashCode是否相等,如果hashCode不相等,那么一定不是同一个对象
* 如果hashCode相等,那么就需要equals方法进一步判断,如果equals返回true,表示对象是同一个
* 如果equals返回false,表示对象不是同一个
*/

public class SetDemo {

public static void main(String[] args) {

HashSet<String> hs = new HashSet<String>();
hs.add("大家好");
hs.add("努力");
hs.add("学习");
hs.add("JAVA");
hs.add("ANDROID");

System.out.println("元素的个数是:" + hs.size());

Iterator<String> it = hs.iterator();
while (it.hasNext()) {

System.out.println(it.next());
}

System.out.println("-------------------------------------");
// ----------存储自定义对象--------------------
HashSet<Person> hs1 = new HashSet<Person>();
Person p1 = new Person("LISI1", 30);
Person p2 = new Person("LISI2", 29);
Person p3 = new Person("LISI3", 32);
Person p4 = new Person("LISHI4", 28);
hs1.add(p1);
hs1.add(p2);
hs1.add(p3);
hs1.add(p4);
System.out.println("一共有元素:" + hs1.size());

Iterator it1 = hs1.iterator();
while (it1.hasNext()) {
Person p = (Person) it1.next();
System.out.println(p);
}
}
}

class Person {
private String name;
private int age;

public Person() {
super();
}

public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}

@Override
public int hashCode() {
return name.hashCode() + age * 31;
}

@Override
public boolean equals(Object obj) {
if (this==obj)
return true;
if(obj!=null && obj.getClass() == Person.class){
Person p = (Person) obj;
return this.name.equals(p.name) && this.age == p.age;
}
return false;
}

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 "Person [name=" + name + ", age=" + age + "]";
}

}

3、TreeSet

public class TreeSet<E> extends AbstractSet<E> implements 
Cloneable, Serializable

基于TreeMap 的 NavigableSet 实现。使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序,具体取决于使用的构造方法。

TreeSet保证元素唯一性的依据:compareTo方法 return 0

第一种排序方式:让元素自身具备比较性。元素需要实现Comparable接口,覆盖Comparable方法。这种方式也称为元素的自然顺序,或者叫默认顺序。

第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的。这时就需要让集合自身具备比较性。
在集合初始化时,就有了比较方式。

当两种排序都存在时,以比较器为主。、

定义一个类,实现Comparator接口,覆盖compare方法

代码演示:

package com.joe.list;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

/**
* TreeSet实现类
* 1、使用元素的自然顺序对元素进行排序
* 2、底层使用TreeMap实现(树型结构)
* 3、在TreeSet集合中存储自定义对象时,该对象必须实现Comparable/Comparator接口
* 4、底层是自然排序,如果要按照存入的顺序输出,重写compareTo()方法,改为“return 1“,如果要倒序输出,重写compareTo()方法,改为“return -1”
*/

public class TreeSetDemo {

public static void main(String[] args) {

Set<String> ts = new TreeSet<String>();
ts.add("小明");
ts.add("小张");
ts.add("小曾");
ts.add("小琪");
System.out.println("元素的个数是:" + ts.size());
Iterator it = ts.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}

System.out.println("----------添加自定义对象------------");
Set<Student> students = new TreeSet<Student>();
Student s1 = new Student("小明", 30);
Student s2 = new Student("小张", 29);
Student s3 = new Student("小曾", 32);
Student s4 = new Student("小琪", 28);
students.add(s1);
students.add(s2);
students.add(s3);
students.add(s4);

students.add(new Student("利亚", 29));
System.out.println("元素的个数是:" + students.size());
Iterator<Student> it1 = students.iterator();
while (it1.hasNext()) {
System.out.println(it1.next());
}

}
}

class Student implements Comparable {
private String name;
private int age;

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public Student() {
super();
}

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 "Student [name=" + name + ", age=" + age + "]";
}

@Override
public int compareTo(Object obj) {
if (!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student) obj;

if (this.age > s.age) { //先比较年龄
return 1;
} else if (this.age < s.age) {
return this.name.compareTo(s.name); //如果年龄相同,在比较名字
}
return -1;
}
}

自定义比较器的代码演示:

package com.joe.list;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

/**
* 当元素自身不具备比较性,或者具备的比较性不是所需要的。这时需要让容器自身具备比较性。 定义了比较器,将比较器对象作为参数传递给TreeSet集合的构造函数
*
* @author joe
*
*/


public class TreeSetDemo2 {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new MyCompare());
ts.add(new Student2("lisi",23));
ts.add(new Student2("lisi1",22));
ts.add(new Student2("lisi2",24));
ts.add(new Student2("lisi3",21));

Iterator it = ts.iterator();
while(it.hasNext()){
Student2 stu = (Student2)it.next();
System.out.println(stu.getName()+"..."+stu.getAge());
}
}

}

//自定义比较器
class MyCompare implements Comparator{
public int compare(Object o1,Object o2){
Student2 s1 = (Student2)o1;
Student2 s2 = (Student2)o2;

int num = s1.getName().compareTo(s2.getName());
if(num==0)
{
//把int类型封装成Integer对象,调用compareTo方法
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
// if(s1.getAge()>s2.getAge())
// return 1;
// if(s1.getAge()==s2.getAge())
// return 0;
// return -1;
}
return num;
}
}

class Student2 implements Comparable {
private String name;
private int age;

public Student2(String name, int age) {
super();
this.name = name;
this.age = age;
}

public Student2() {
super();
}

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 "Student [name=" + name + ", age=" + age + "]";
}

@Override
public int compareTo(Object obj) {
if (!(obj instanceof Student2))
throw new RuntimeException("不是学生对象");
Student2 s = (Student2) obj;

if (this.age > s.age) { // 先比较年龄
return 1;
} else if (this.age < s.age) {
return this.name.compareTo(s.name); // 如果年龄相同,在比较名字
}
return -1;
}
}

练习:

package com.joe.list;

import java.util.Comparator;
import java.util.Iterator;
import java.util.TreeSet;

/**
* 练习:按照字符串长度排序
*
* @author joe
*
*/


public class TreeSetPractice {
public static void main(String[] args) {
TreeSet ts = new TreeSet(new StrLenComparator());

ts.add("abc");
ts.add("abec");
ts.add("at");
ts.add("abcwrw");

Iterator it = ts.iterator();

while (it.hasNext()) {
System.out.println(it.next());
}
}

}

class StrLenComparator implements Comparator {
//重写compare方法
public int compare(Object o1, Object o2) {
String s1 = (String) o1;
String s2 = (String) o2;
int num = new Integer(s1.length()).compareTo(new Integer(s2.length()));
if (num == 0)
return s1.compareTo(s2);
return num;
}
}

4、LinkedHashSet

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

具有可预知迭代顺序的set接口的哈希表和链接列表实现。此实现与 HashSet 的不同之外在于,后者维护着一个运行于所有条目的双重 链接列表。此链接列表定义了迭代顺序,即按照将元素插入到set中的顺序(插入顺序)进行迭代。注意:插入顺序不受在set中重新插入的元素的影响。(如果在s.contains(e)返回true后立即调用s.add(e),则元素e会被重新插入到sets中。)

代码演示:

package com.joe.list;

import java.util.LinkedHashSet;
import java.util.Set;

/* LinkedHashSet实现类 1、使用哈希表+双向链表实现 2、会以插入的顺序输出 3、底层是使用LinkedHashMap实现
* 4、是HashSet的子类
*/

public class LinkedHashSetDemo {
public static void main(String[] args) {
Set<Student> set = new LinkedHashSet<Student>();
Student s1 = new Student("小明", 18);
Student s2 = new Student("小张", 19);
Student s3 = new Student("小红", 17);
set.add(s3);
set.add(s2);
set.add(s1);
set.add(new Student("小红", 17));
System.out.println(set);
}

}

class Student implements Comparable {
private String name;
private int age;

public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}

public Student() {
super();
}

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 "Student [name=" + name + ", age=" + age + "]";
}

@Override
public int compareTo(Object obj) {
if (!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s = (Student) obj;

if (this.age > s.age) { // 先比较年龄
return 1;
} else if (this.age < s.age) {
return this.name.compareTo(s.name); // 如果年龄相同,在比较名字
}
return -1;
}
}