一般来说,如果被别人问到一个问题:谁和谁的区别,在回答问题的时候,第一步应该回答的是他们之间有什么相似之处,充分变现出对技术的理解。
相同点:List
和Set
都是Collection
集合的子级接口!所以都具有Collection
这个借口所定义的所有的方法,比如添加和移除元素。
不同点:List
是序列的,主要表现为其中的各元素在内存中是存在顺序规则的;另外,List
中的元素是可以重复的,即可以向同一个List
集合中反复添加相同的数据;
Set
是散列的,主要表现为其中的各元素在内存中的位置是散列的,如果使用不同的实现类来存储数据,最终在显示Set
集合中的所有元素时,显示结果可能是无序的(HashSet
),或根据排序规则进行排列的(TreeSet
),或根据添加顺序进行排列的(LinkedHashSet
);(注意并不是说整个集合是,而是最后的显示结果,看到的结果是这样的)。所以不能直接说Set是无序的。
另外,Set
中的元素是不可重复的,即不可以向同一个Set
集合中反复添加相同的数据,关于“是否相同”,取决于equals()
的对比结果与hashCode()
值的对比,如果2个对象的equals()
对比为true
,并且hashCode()
值相等,则视为“相同”!
所以,是否相同,取决于hashCode和equals方法,是先比较的hashCode再比较equals,如果hashCode相同,再比较equals,如果hashCode不同,就不比较了。
一、注意:不要用有序和无序来描述List集合和Set集合。
比如Set集合,要看用的是哪个实现类:
(1)使用HashSet作为实现类,结果是无序的;
(2)使用TreeSet作为实现类,结果为12345有序的;
(3)使用LinkedHashSet实现类,结果与添加顺序一致;
所以,直接说Set是无序的,这种说法是不精准的。
详细如下:
1.使用HashSet作为实现类,输出为:[str-4, str-5, str-2, str-3, str-1],显示结果是无序的;
package cn.tedu.spring;
import java.util.HashSet;
import java.util.Set;
public class CollectionDemo {
public static void main(String[] args) {
Set<String> strings = new HashSet<String>();
strings.add("str-1");
strings.add("str-5");
strings.add("str-3");
strings.add("str-2");
strings.add("str-4");
System.out.println(strings);
//输出为:[str-4, str-5, str-2, str-3, str-1]
}
}
2.使用TreeSet作为实现类,输出为[str-1, str-2, str-3, str-4, str-5],显示结果是有序的;
package cn.tedu.spring;
import java.util.Set;
import java.util.TreeSet;
public class CollectionDemo {
public static void main(String[] args) {
Set<String> strings = new TreeSet<String>();
strings.add("str-1");
strings.add("str-5");
strings.add("str-3");
strings.add("str-2");
strings.add("str-4");
System.out.println(strings);
//输出为:[str-1, str-2, str-3, str-4, str-5]
}
}
3.使用 LinkedHashSet作为实现类,输出为:[str-1, str-5, str-3, str-2, str-4],和添加的顺序一致,显示结果是有序的;
package cn.tedu.spring;
import java.util.LinkedHashSet;
import java.util.Set;
public class CollectionDemo {
public static void main(String[] args) {
Set<String> strings = new LinkedHashSet<String>();
strings.add("str-1");
strings.add("str-5");
strings.add("str-3");
strings.add("str-2");
strings.add("str-4");
System.out.println(strings);
//输出为:[str-1, str-5, str-3, str-2, str-4]
}
}
所以,直接说Set是无序的,这种说法是不精准的。
而对于Set
中的元素是不可重复的:
演示代码:
package cn.tedu.spring;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
public class CollectionDemo {
public static void main(String[] args) {
Set<String> strings = new LinkedHashSet<String>();
strings.add("str-1");
strings.add("str-5");
strings.add("str-3");
strings.add("str-2");
strings.add("str-2");
strings.add("str-2");
strings.add("str-2");
strings.add("str-2");
strings.add("str-4");
System.out.println(strings);
//重点关注Set集合能不能重复,是哪个实现类不重要
Set<Student> students = new HashSet<Student>();
students.add(new Student("Mike", 18));
students.add(new Student("Frank", 20));
students.add(new Student("Frank", 20));
//这行代码是复制上一行的
//这个相同的student,是可以加入进去的,但绝对不是因为是new出来的这个原因
students.add(new Student("Frank", 25));
students.add(new Student("Joe", 25));
//为了不一横排输出,写一个遍历好看些
for (Student student : students) {
System.out.println(student);
}
}
}
class Student {
public String name;
public int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//下面的两个重写方法,都是用Source来生成的,一键生成
//而开发工具不同,可能生成的代码是不同的
//生成的这两个方法,目的是为了加入的属性值的内容相同,即使是new出来的对象,也看做同一个数据,也不能加入集合
//各个属性,比如name和age的值相同,它的hashcode就一定相同,equals的对比结果也一定是true
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
//下面这个是自动生成的
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
如何输出Set集合中的单个元素?
一般Set集合,就是遍历输出,挨个输出里面的所有元素,
只有一种情况是输出Set中的单个元素,就是确定这Set的实现类是LinkedHashSet,因为Linked的元素存储结构是一个链一个的,所以在LinkedHashSet里面的数据其实是有下标的,或者说是有索引位置的,所以只有这种Set我们才会在当中获取第3个元素或第5个元素。如果是一般的HashSet或TreeSet我们根本就不考虑要获取其中的某一个。