androidlist替换元素_Java集合(⼆)——Set集合、List集合
和Colle。。。
⼀、前⾔
在 Java 集合(⼀)中我们已经讲了 Collection 集合接⼝、Iterator 迭代器和泛型,今天我们来讲 Set 集合、List 集合和 Collections ⼯具类。⼆、Set 集合
Set 接⼝继承⾃ Collection 接⼝,它与 Collection 接⼝中的⽅法基本⼀致,并没有对 Collection 接⼝进⾏功能上的扩展,只是⽐ Collection 接⼝更加严格了,与 List 集合不同的是,Set 集合不允许存储重复的元素,⽽且 Set 集合是没有索引的。
Set 集合有多个⼦类,这⾥我们介绍其中的 HashSet 与 LinkedHashSet 这两个集合。
Set 集合取出元素的⽅式可以采⽤:迭代器、增强 for。
2.1、HashSet 集合
HashSet 集合实现了 Set 接⼝,⾸先 Set 集合有的特点它都有,同时它还有以下特点:是⼀个⽆序的集合,存储元素和取出元素的顺序有可能不⼀致。
底层是⼀个哈希表结构,查询的速度⾮常的快。HashSet 集合代码演⽰如下所⽰:public class SetDemo01 {
public static void main(String[] args) {
Set set = new HashSet<>();
// 使⽤ add() ⽅法添加元素
set.add(1);
set.add(3);
set.add(2);
set.add(1);
// 使⽤迭代器遍历集合
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
System.out.());
}
// 使⽤增强 for 循环遍历
for (Integer integer : set) {
System.out.println(integer);
}
}
}
2.2、哈希值
哈希值是⼀个⼗进制的整数,由系统随机给出,实际上就是对象的地址值,是⼀个逻辑地址,是模拟出来的地址,不是数据实际存储的物理地址。在 Object 类有⼀个⽅法 hashCode(),可以获取对象的哈希值。
hashCode() ⽅法源码如下:(native 代表该⽅法调⽤的是本地操作系统的⽅法)public native int hashCode();
toString() 的源码如下:public String toString() {
return getClass().getName() + "@" + HexString(hashCode());
}
可以看出 toString() 也调⽤了 hashCode() 并将其转化为⼗六进制。哈希值代码演⽰如下所⽰:public class Person extends Object { public static void main(String[] args) {
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1); // 1163157884
Person p2 = new Person();
int h2 = p2.hashCode();
System.out.println(h2); // 1956725890
/**
* toString() 的源码
* public String toString() {
* return getClass().getName() + "@" + HexString(hashCode());
* }
*/
System.out.println(p1); // com.zjgsu.Set.Person@4554617c
System.out.println(p2); // com.zjgsu.Set.Person@74a14482
java的tostring方法/**
* String 类的哈希值
* String 类重写了 hashCode() 所以下⾯两个哈希值是⼀样的
*/
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
}
}
2.3、哈希表
在 JDK1.8 之前哈希表 =数组 + 链表,但是在JDK1.8之后,哈希表 = 数组 + 链表 + 红⿊树(提⾼查询效率)。具体如下图所⽰:
2.4、Set 集合存储元素不重复的原理
我们先来执⾏以下下⾯的代码:public class SetDemo02 {
public static void main(String[] args) {
HashSet set = new HashSet ();
String s1 = new String("abc");
String s2 = new String("abc");
set.add(s1);
set.add(s2);
set.add("重地");
set.add("通话");
set.add("abc");
System.out.println(set); // [重地, 通话, abc]
}
}
打印结果如下所⽰:(可以看到 "abc" 只有⼀个)
我们根据代码来分析⼀下:HashSet set = new HashSet ():现在我们已经知道hashSet 底层是⼀个哈希表,所以这句代码会创建⼀个哈希表。
set.add(s1):add() ⽅法会调⽤ s1 的 hashCode() ⽅法。计算字符串 “abc” 的哈希值,哈希值是 96354,在集合中有没有 96354 这个哈希值的元素,发现没有,就把 s1 存储到集合中。
set.add(s2):add() ⽅法会调⽤ s2 的 hashCode() ⽅法。计算字符串 “abc” 的哈希值,哈希值是 96354,在集合中有没有 96354 这个哈希值的元素,发现有(哈希冲突),s2 会调⽤ equals() ⽅法和哈希值相同的元素进⾏⽐较,s2.equals(s1) 返回 true,两个元素相同,就不会把s2 存储到集合中。
set.add("重地");:add() ⽅法会调⽤ "重地" 的 hashCode() ⽅法。计算字符串 “重地” 的哈希值,哈希值是 1179395,在集合中有没有1179395 这个哈希值的元素,发现没有,就把"重地"存储到集合中。
set.add("通话");:add() ⽅法会调⽤ "通话" 的 hashCode() ⽅法。计算字符串 “通话” 的哈希值,哈希值是 1179395,在集合中有没有1179395 这个哈希值的元素,发现有(哈希冲突),"通话" 会调⽤ equals() ⽅法和哈希值相同的元素进⾏⽐较,"通话".equals("重地") 返回false,两个元素不同,就把"通话"存储到集合中。
最后哈希表中的元素如下所⽰:
通过上述步骤的分析,已经很明了的说明了 Set 集合元素不重复的原理,前提就是存储的元素必须重写 hashCode() ⽅法和 equals() ⽅法。
2.5、HashSet 集合存储⾃定义类型元素
给 HashSet 中存放⾃定义类型元素时,需要重写对象中的hashCode() ⽅法和 equals() ⽅法,建⽴⾃⼰的⽐较⽅式,才能保证 HashSet 集合中的对象唯⼀。我们来看个例⼦,如下所⽰: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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public static void main(String[] args) { HashSet set = new HashSet<>(); Student s1 = new Student("张三", 18); Student s2 = new Student("张三", 18); Student s3 = new Student("张三", 30); System.out.println(s1.hashCode()); System.out.println(s2.hashCode()); System.out.println(s3.hashCode()); set.add(s1);
set.add(s2);
set.add(s3);
System.out.println(set);
}
}
打印结果如下所⽰:
可以看到,如果没有重写 hashCode() ⽅法和 equals() ⽅法,那么三个⼈是都会打印出来的,因为这时候他们的哈希值是不同的。
给 Student 类重写 hashCode() ⽅法和 equals() ⽅法,具体如下所⽰:@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
打印结果如下所⽰:
可以看到,重写了 hashCode() ⽅法和 equals() ⽅法之后,就把重复的 Student 对象去掉了。
2.6、LinkedHashSet 集合
我们知道 HashSet 保证元素唯⼀,可是元素存放进去是没有顺序的,那么我们要保证有序,怎么办呢?在 HashSet 下⾯有⼀个⼦类LinkedHashSet,它是链表和哈希表组合的⼀个数据存储结构,它多了⼀条链表⽤来记录元素的存储顺序,所以 LinkedHashSet 是有序的。LinkedHashSet 集合代码演⽰如下所⽰:public class LinkedHashSetDemo01 {
public static void main(String[] args) {
HashSet set = new HashSet<>();
set.add("abc");
set.add("www");
set.add("zz");
set.add("qq");
set.add("it");
System.out.println(set);
LinkedHashSet linkedSet = new LinkedHashSet<>();
linkedSet.add("abc");
linkedSet.add("www");
linkedSet.add("zz");
linkedSet.add("qq");
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论