Set集合和List集合的区别?
Set集合:不允许元素重复,唯一的(元素可以为null) ,不能保证迭代的顺序恒久不变(底层哈希表和hascode)
无序(存储和取出不一致)
List:允许元素重复,并且存储特点:有序性(存储和取出一致)
看源码:
@author Administrator
HashSet集合的add方法底层依赖于双列集合HashMap,它依赖于两个方法,HashCode()方法和equals()方法
先比较字符串的hashCode码值,看hashCode码值是否一样,再使用equals()方法
如果hasCode码值一样,还要比较内容是否相同,由于String本身重写了equals方法,所以不需要再重写了!
如果开发中要使用集合排序,使用TreeSet集合(红黑树结构)
自然排序
选择器排序
LinkedHashSet集合:
底层由链接列表和哈希表组成
元素的唯一性,是由哈希表决定的(hashCode()和equals())
元素的迭代有序,存储和取出一致,是由链接链表决定
TreeSet:
可以保证元素唯一(不重复)并且元素有序(Integer类型的元素自然升序(有小到大排序))
自然排序
比较器排序
如何排序
按照学生的年龄从小到大进行排序 (主要条件)
唯一性:
按照姓名的长度从小到大进行排序 :主要条件
自然排序:自定义的类实现Compareable接口,然后创建TreeSet对象,通过无参构造形式创建对象
比较器排序 :public TreeSet(Comparator<E> comparator)
比较器排序的两种方式:
1)自定义一个类,该类实现Comparator接口,重写Comparator接口中的compare()方法
2)直接使用接口的匿名内部类
TreeSet集合保证元素唯一,是看返回值是否为0
保证元素进行排序,两种排序方式
通过比较器排序的方式去遍历Student对象,并且按照姓名长度进行排序
Set集合:不允许元素重复,唯一的(元素可以为null) ,不能保证迭代的顺序恒久不变(底层哈希表和hascode)
无序(存储和取出不一致)
List:允许元素重复,并且存储特点:有序性(存储和取出一致)
通过Set集合存储字符串并遍历
代码示例
package test;
import java.util.HashSet;
import java.util.Set;
public class TestDemo4 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Set<String> set = new HashSet<String>();
set.add("hello");
set.add("world");
set.add("java");
set.add("hello");
set.add("world");
set.add("java");
for (String string : set) {
System.out.println(string);
}
}
}
发现Set集合存储元素的时候,可以保证元素的唯一性,原因什么?
看源码:
@author Administrator
HashSet集合的add方法底层依赖于双列集合HashMap,它依赖于两个方法,HashCode()方法和equals()方法
先比较字符串的hashCode码值,看hashCode码值是否一样,再使用equals()方法
如果hasCode码值一样,还要比较内容是否相同,由于String本身重写了equals方法,所以不需要再重写了!
用Set集合存储自定义对象并遍set集合存储自定义对象并遍历
现在是自定义的类,HashSet集合的add()方法本身依赖于hashCode()和equals()方法
在Student类中并没重写这两个方法,解决,重写这两个方法
代码示例
package org.westos_01;
public class Student {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
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 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))// !(false)==true 进入if中 返回fale
return false;
return true;
}
}
public class SetDemo3 {
public static void main(String[] args) {
Set<Student> set = new HashSet<Student>();
// 创建学生对象
Student s1 = new Student("高圆圆", 27);
Student s2 = new Student("高圆圆", 28);
Student s3 = new Student("文章", 30);
Student s4 = new Student("马伊琍", 39);
Student s5 = new Student("高圆圆", 27);
// 存储到集合中
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
set.add(s5);
// 遍历
for (Student s : set) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
HashSet集合的add()方法源码分析
inteface Collection{
}
interface Set extends Collection{
}
class HashSet implements Set{
private HashMap<E,Object> map;
//创建HashSet集合对象的时候,起始底层创建了一个HashMap集合对象
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
return map.put(e, PRESENT)==null; //add方法底层依赖于HashMap集合的
}
}
class HashMap<K,V> implements Map<K,V>{
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
//putVal方法
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node<K,V>[] tab; Node<K,V> p; int n, i; //Node是一种键值对对象
//判断哈希表示是为空,如果为空.有set集合元素的情况,哈希表不为空
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
Node<K,V> e; K k; //k--->传入的元素
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
//一些判断,主要还是eqauls()方法
e = p; /e =p = key
else if (p instanceof TreeNode)
e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key mapping:映射 (Servlet servlet-mapping)
V oldValue = e.value; //e.value=key ="hello" ,"world","java","world","java"
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue; //返回的oldValue:永远是第一次存储的哪个元素
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
}
哈希方法
static final int hash(Object key) { //传入的字符串元素 "hello","java","world" ,"hello"....
int h; //哈希码值
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); //无符号右移
底层依赖于第一个方法hashCode()
计算机底层运算数据:补码
}
Set<String> set = new HashSet<String>() ;
set.add("hello") ;
set.add("java") ;
set.add("world");
set.add("hello") ;
set.add("java") ;
set.add("world");
如果在开发中,要保证元素的唯一性,并且还要保证元素有序(存储和取出一致),使用LinkedHashSet集合
如果开发中要使用集合排序,使用TreeSet集合(红黑树结构)
自然排序
选择器排序
LinkedHashSet集合:
底层由链接列表和哈希表组成
元素的唯一性,是由哈希表决定的(hashCode()和equals())
元素的迭代有序,存储和取出一致,是由链接链表决定
代码示例
package test;
import java.util.LinkedHashSet;
public class TestDemo5 {
public static void main(String[] args) {
// TODO Auto-generated method stub
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
linkedHashSet.add("hello");
linkedHashSet.add("java");
linkedHashSet.add("world");
linkedHashSet.add("world");
linkedHashSet.add("java");
linkedHashSet.add("hello");
linkedHashSet.add("java");
linkedHashSet.add("world");
linkedHashSet.add("world");
linkedHashSet.add("java");
linkedHashSet.add("hello");
linkedHashSet.add("java");
linkedHashSet.add("world");
linkedHashSet.add("world");
linkedHashSet.add("java");
for (String string : linkedHashSet) {
System.out.println(string);
}
}
}
TreeSet集合通常情况下是以自然顺序对集合中的元素进行排序
TreeSet:
可以保证元素唯一(不重复)并且元素有序(Integer类型的元素自然升序(有小到大排序))
自然排序
比较器排序
给TreeSet集合存储以下元素:20,23,22,18,17,19,24
代码示例
package test;
import java.util.TreeSet;
public class TestDemo6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeSet<Integer> ts = new TreeSet<Integer>();
ts.add(20);
ts.add(22);
ts.add(18);
ts.add(23);
ts.add(24);
ts.add(17);
ts.add(19);
ts.add(18);
ts.add(24);
ts.add(20);
ts.add(22);
ts.add(18);
ts.add(23);
ts.add(24);
ts.add(17);
ts.add(19);
ts.add(18);
ts.add(24);
for (Integer integer : ts) {
System.out.println(integer + " ");
}
}
}
需求:使用TreeSet集合存储自定义对象(Student类型),并遍历!
如何排序
按照学生的年龄从小到大进行排序 (主要条件)
唯一性:
如果所有的成员变量的值是一样的,则认为是同一个对象
在自定义类型中必须实现Comparable接口,在类中重写ComparaTo()方法
代码示例
package org.westos_03;
import java.util.TreeSet;
/**
* 需求:使用TreeSet集合存储自定义对象(Student类型),并遍历! 如何排序 按照学生的年龄从小到大进行排序 (主要条件) 唯一性:
* 如果所有的成员变量的值是一样的,则认为是同一个对象
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
// 创建TreeSet集合对象
TreeSet<Student> ts = new TreeSet<Student>();// 无参构造自然排
// 创建学生对象
Student s1 = new Student("gaoyuanyuan", 27);
Student s2 = new Student("liushishi", 38);
Student s3 = new Student("gaoyuanyuan", 28);
Student s4 = new Student("wanglihong", 35);
Student s5 = new Student("wanglihong", 30);
Student s6 = new Student("fengqingy", 38);
Student s7 = new Student("gaoyuanyuan", 27);
// java.lang.ClassCastException: org.westos_03.Student cannot be cast to
// java.lang.Comparable
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
package org.westos_03;
//对于自定义的类型,要实现自然排序,自定义的类型必须实现Comparable
//实现接口中的方法,compareTo() :比较方法
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
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 int compareTo(Student s) { // 源码 cmp = k.compareTo(t.key)
// 主要条件:按照年龄从小到大进行排序
int num = this.age - s.age; // 如果年龄相等,不一定是同一个人
// 需要自己分析次要条件;
// 年龄相同,姓名的内容不一定相同,比较姓名
int num2 = num == 0 ? this.name.compareTo(s.getName()) : num; // 如果年龄不相同,则返回num(年龄差) num2=num;
return num2;
}
}
package org.westos_03;
import java.util.TreeSet;
/**
* 需求:使用TreeSet集合存储自定义对象(Student类型),并遍历! 如何排序 按照学生的年龄从小到大进行排序 (主要条件) 唯一性:
* 如果所有的成员变量的值是一样的,则认为是同一个对象
*/
public class TreeSetDemo2 {
public static void main(String[] args) {
// 创建TreeSet集合对象
TreeSet<Student> ts = new TreeSet<Student>();// 无参构造自然排
// 创建学生对象
Student s1 = new Student("gaoyuanyuan", 27);
Student s2 = new Student("liushishi", 38);
Student s3 = new Student("gaoyuanyuan", 28);
Student s4 = new Student("wanglihong", 35);
Student s5 = new Student("wanglihong", 30);
Student s6 = new Student("fengqingy", 38);
Student s7 = new Student("gaoyuanyuan", 27);
// java.lang.ClassCastException: org.westos_03.Student cannot be cast to
// java.lang.Comparable
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
TreeSet集合存储自定义对象(Student)
按照姓名的长度从小到大进行排序 :主要条件
代码示例
package org.westos_04;
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
super();
}
public Student(String name, int age) {
super();
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;
}
// TreeSet集合保证元素的唯一性,看返回值是否为0
@Override
public int compareTo(Student s) {
// return 0;
// 按照姓名的长度进行比较(默认从小到大)
int num = this.getName().length() - s.getName().length();
// ( 自己分析)次要条件
// 如果姓名的长度一样,还要比较他们的内容是否相同
int num2 = num == 0 ? this.getName().compareTo(s.getName()) : num;
// 如果姓名的长度和姓名的内容都一致,也不能保证就是同一个人,还要比较年龄
int num3 = num2 == 0 ? this.age - s.age : num2;
return num3;
}
}
package org.westos_04;
import java.util.TreeSet;
/*TreeSet集合存储自定义对象(Student)
*
* 按照姓名的长度从小到大进行排序 :主要条件*/
public class TreeSetDemo {
public static void main(String[] args) {
// 创建TreeSet集合,实现对该类型自然排序
TreeSet<Student> ts = new TreeSet<Student>();
// 创建学生对象
Student s1 = new Student("gaoyuanyuan", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wuqilong", 40);
Student s4 = new Student("liushishi", 28);
Student s5 = new Student("fengqingy", 29);
Student s6 = new Student("gaoyuanyuan", 22);
Student s7 = new Student("gaoyuanyuan", 27);
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
// 遍历
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
TreeSet集合的构造方式不同,使用的排序也不同
自然排序:自定义的类实现Compareable接口,然后创建TreeSet对象,通过无参构造形式创建对象
比较器排序 :public TreeSet(Comparator<E> comparator)
比较器排序的两种方式:
1)自定义一个类,该类实现Comparator接口,重写Comparator接口中的compare()方法
2)直接使用接口的匿名内部类
TreeSet集合保证元素唯一,是看返回值是否为0
保证元素进行排序,两种排序方式
通过比较器排序的方式去遍历Student对象,并且按照姓名长度进行排序
代码示例
package org.westos.comparator;
import java.util.Comparator;
public class MyComparator implements Comparator<Student> {
@Override
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
// return 0;
int num1 = o1.getName().length() - o2.getName().length();
int num2 = num1 == 0 ? o1.getName().compareTo(o2.getName()) : num1;
int num3 = num2 == 0 ? (o1.getAge() - o2.getAge()) : num2;
return num3;
}
}
package org.westos.comparator;
public class Student {
private String name;
private int age;
public Student() {
super();
// TODO Auto-generated constructor stub
}
public Student(String name, int age) {
super();
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;
}
}
package org.westos.comparator;
import java.util.Comparator;
import java.util.TreeSet;
import org.westos_05.Student;
public class TreeSetDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
// TreeSet<Student> treeSet = new TreeSet<Student>(new MyComparator());
TreeSet<Student> treeSet = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
// TODO Auto-generated method stub
// return 0;
int num1 = o1.getName().length() - o2.getName().length();
int num2 = num1 == 0 ? o1.getName().compareTo(o2.getName()) : num1;
int num3 = num2 == 0 ? (o1.getAge() - o2.getAge()) : num2;
return num3;
}
});
Student s1 = new Student("gaoyuanyuan", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wuqilongdaw", 40);
Student s4 = new Student("liushishi", 28);
Student s5 = new Student("fengqingy", 29);
Student s6 = new Student("gaoyuanyuan", 22);
Student s7 = new Student("gaoyuanyuan", 27);
treeSet.add(s1);
treeSet.add(s2);
treeSet.add(s3);
treeSet.add(s4);
treeSet.add(s5);
treeSet.add(s6);
treeSet.add(s7);
for (Student student : treeSet) {
System.out.println(student.getName() + "----" + student.getAge());
}
}
}