Set
Set是Collection的子接口,其定义如下:
public interface Set<E> extends Collection<E>
与List相同,此接口也使用了泛型,使用时必须指定具体的类型。
Set常见的实现子类:HashSet、TreeSet
HashSet
HashSet是Set的子类,其类定义如下:
public class HashSet<E>
extends AbstractSet<E>
implements Set<E>, Cloneable, java.io.Serializable
HashSe是无序的,其内部结构是散列表。
HashSet类的常用方法如下:
方法 | 类型 | 描述 |
---|---|---|
boolean add(E e) | 普通方法 | 添加元素 |
boolean remove(Object o) | 普通方法 | 删除元素 |
boolean contains(Object o) | 普通方法 | 是否包含某元素 |
boolean add(E e)
添加元素
栗子:
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("张三");
set.add(new String("张三"));
String str = new String("张三");
set.add(str);
//测试存放相同的元素
set.add("李四");
set.add("王五");
for (String s : set) {
System.out.println(s);
}
}
程序运行结果:
李四
张三
王五
从结果可以看出HashSet中不能存放相同的元素,且HashSet内部的元素是无序的。
问:HashSet是如何判断重复的元素呢?
答:散列码(哈希编码)。
众所周知Object是所有类的父类,在Object中有一个hashCode()方法来得到散列码。
每一个对象都有一个默认的散列码(哈希编码)。
对于自定义的类,想要达到去重的效果存放于HashSet集合中,需要重写其hashCode()方法。
boolean remove(Object o) 和 boolean contains(Object o)
删除元素 和 判断元素是否存在
栗子:
public static void main(String[] args) {
Set<String> set = new HashSet<>();
set.add("张三");
set.add("李四");
set.add("王五");
set.add("赵五");
System.out.println("删除元素前");
for (String s : set) {
System.out.println(s);
}
System.out.println("删除元素后");
set.remove("张三");
System.out.println(set.contains("张三"));
for (String s : set) {
System.out.println(s);
}
}
程序运行结果:
删除元素前
李四
张三
王五
赵五
删除元素后
false
李四
王五
赵五
TreeSet
TreeSet是Set的子类,其类定义如下:
public class TreeSet<E> extends AbstractSet<E>
implements NavigableSet<E>, Cloneable, java.io.Serializable
TreeSet是有序的。
TreeSet常用方法同HashSet类的常用方法
栗子:
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("王五");
set.add("张三");
set.add("赵六");
set.add("李四");
for (String s : set) {
System.out.println(s);
}
}
程序运行结果:
张三
李四
王五
赵六
从栗子中可以清楚地看到,就算添加数据时没有顺序,其输出结果还是有序的。
问:TreeSet是如何判断重复的元素呢?
答:对象的equals()方法返回值,或CompareTo()方法返回值。
问:TreeSet是如何实现的排序呢?
答:TreeSet存储对象的时候, 可以排序, 但是需要指定排序的算法。
对于上述栗子,我们存储的对象是String,String内部有默认排序。
对于自定义的类,必须实现Comparable接口并重写其compareTo()方法。
自定义的类在TreeSet中使用
因为TreeSet中的元素都是有序排放的。
所以对于自定义的类想要在TreeSet中使用
- 实现Comparable接口
- 重写其compareTo()方法
- 在方法中指定排序规则
栗子:
public class Test14 {
public static void main(String[] args) {
Set<Ball> set = new TreeSet<>();
set.add(new Ball("C",42.3));
set.add(new Ball("B",32.3));
set.add(new Ball("A",22.3));
set.add(new Ball("A",22.3));
set.add(new Ball("D",22.3));
for (Ball ball : set) {
System.out.println(ball);
}
}
}
class Ball implements Comparable {
private String name;
private double sale;
public Ball(String name, double sale) {
this.name = name;
this.sale = sale;
}
@Override
public int compareTo(Object o) {//compareTo方法也叫比较器
Ball b = (Ball) o;//向下转型
//this指向调用compareTo()方法的对象
if (this.sale > b.sale) {//大返回-1
return 1;
} else if (this.sale < b.sale) {
return -1;//小返回-1
} else {
return 0;//相等返回0
}
}
@Override
public String toString() {
return "Ball{" +
"name='" + name + '\'' +
", sale=" + sale +
'}';
}
}
程序运行结果:
Ball{name='A', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='C', sale=42.3}
对于上述栗子,添加元素时是无序的,但输出会自动调用compareTo()方法(比较器),然后按照规则排序。
但栗子中的比较器仅仅是根据sale属性进行排序,所以会导致存在D被过滤掉。
至此,修改栗子如下:
public class Test14 {
public static void main(String[] args) {
Set<Ball> set = new TreeSet<>();
set.add(new Ball("C",42.3));
set.add(new Ball("B",32.3));
set.add(new Ball("A",22.3));
set.add(new Ball("A",22.3));//重复的内容
set.add(new Ball("D",22.3));
for (Ball ball : set) {
System.out.println(ball);
}
}
}
class Ball implements Comparable {
private String name;
private double sale;
public Ball(String name, double sale) {
this.name = name;
this.sale = sale;
}
@Override
public int compareTo(Object o) {
Ball b = (Ball) o;//向下转型
if (this.sale > b.sale) {//this指向调用compareTo()方法的对象
return 1;
} else if (this.sale < b.sale) {
return -1;
} else {//如果sale属性相等就比较name属性
return this.name.compareTo(b.name);//使用String类内部默认的比较器进行字符串比较
}
}
@Override
public String toString() {
return "Ball{" +
"name='" + name + '\'' +
", sale=" + sale +
'}';
}
}
程序运行结果:
Ball{name='A', sale=22.3}
Ball{name='D', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='C', sale=42.3}
从结果可以发现,D正确的出现了,并且也成功去重。
但此时的去重只是依靠Comparable接口完成的。
如果将TreeSet集合换成HashSet集合也会出现重复的内容。
想要真正的实现去重,必须重写equals() 和 hashCode()
至此,修改栗子如下:
public class Test14 {
public static void main(String[] args) {
Set<Ball> set = new HashSet<>();
set.add(new Ball("C", 42.3));
set.add(new Ball("B", 32.3));
set.add(new Ball("A", 22.3));
set.add(new Ball("A", 22.3));
set.add(new Ball("D", 22.3));
for (Ball ball : set) {
System.out.println(ball);
}
}
}
class Ball {//不用比较器的去重
private String name;
private double sale;
public Ball(String name, double sale) {
this.name = name;
this.sale = sale;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;//地址值相同返回T
if ( !(o instanceof Ball)) return false;//属于Ball或Ball子类的取反 返回F
Ball ball = (Ball) o;//向下转型
if (this.name.equals(ball.name) &&this.sale== ball.sale) return true; //全部属性相等 是一个对象
else return false;//全部属性不相等 不是一个对象
}
@Override
public int hashCode() {
return Objects.hash(name, sale);
}
@Override
public String toString() {
return "Ball{" +
"name='" + name + '\'' +
", sale=" + sale +
'}';
}
}
程序运行结果:
Ball{name='D', sale=22.3}
Ball{name='B', sale=32.3}
Ball{name='A', sale=22.3}
Ball{name='C', sale=42.3}
标签:set,Java,name,sale,第十四天,add,Set,Ball,String
From: https://www.cnblogs.com/Ocraft/p/17805610.html