①. 无序性!=随机性(正在的无序性是指元素在底层存储的位置是无序的)
②. 不可重复性:当向set中添加进相同的元素的时候,后面的这个不能添加进去
③. 没有带索引的方法,所以不能用普通for循环遍历
④. 底层数据结构是哈希表
HashSet<String>hs=new HashSet<>();
boolean b1=hs.add("a");
boolean b2=hs.add("a");
hs.add(null);
//[null, a]
System.out.println(hs); //HashSet的继承体系中,有重写toString()方法
System.out.println(b1);//true
System.out.println(b2);//false
//只要能用迭代器迭代的,就可以使用增强for循环遍历
for(String str:hs){
System.out.println(str);//[null,a]
}
①. 哈希值是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
②. Object类中有一个方法可以获取对象的哈希值
public int hashCode():返回对象的哈希码值
③. 特点:
[ 掌握关于equals方法和hashCode方法底层实现原理 ]
/*
public static int hashCode(Object a[]) {
if (a == null)
return 0;
int result = 1;
for (Object element : a)
result = 31 * result + (element == null ? 0 : element.hashCode());
return result;
}
为什么是31?
1.31是质数,质数是能被1和它本身整除的数
2.31这个数既不大也不小
3.31这个数好算,2的5次方-1,向左移动5位数-1
* */
@Override
public boolean equals(Object o) {
if (this == o) return true;//调用的对象和传入的对象是同一个对象,直接返回true
if (o == null || getClass() != o.getClass()) return false;//传入的对象为空或者字节码文件不相同,返回false
Person person = (Person) o;//向下转型
return age == person.age &&
Objects.equals(name, person.name);
//如果调用对象的年龄和传入对象的年龄 相同并且 调用对象的姓名和传入对象的姓名相同返回true
}
①. 哈希表和链表实现的Set接口,具有可预测的迭代次序
②. 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
③. 由哈希表保证元素唯一,也就是说没有重复的元素
@Test
public void testLinkHashSet(){
Set set=new LinkedHashSet();
set.add(123);
set.add(456);
set.add("AAA");
set.add("BBB");
set.add(null);
Iterator iterator=set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());//123 456 AAA BBB null
}
//将集合中重复的元素去掉
@Test
public void fun7(){
ArrayList<String>list=new ArrayList<>();
list.add("AAA");
list.add("AAA");
list.add("AAA");
list.add("AAA");
list.add("AAA");
list.add("AAA");
list.add("BBB");
list.add("BBB");
list.add("CCC");
list.add("CCC");
getSingle(list);
// 打印
System.out.println(list);
}
public static void getSingle(ArrayList<String> list) {
/*LinkedHashSetlhs=new LinkedHashSet<>();
Iterator iterator = list.iterator();
while(iterator.hasNext()){
lhs.add(iterator.next());
}
for(String lhs2:lhs){
System.out.print(lhs2+"\t");
}*/
//1.创建一个LinkedHashSet集合
LinkedHashSet<String>lhs=new LinkedHashSet<>();
//2.将List集合中所有的元素添加到LinkedHashSet集合
lhs.addAll(list);
//3.将List 集合中元素清除
list.clear();
//4.将LinkedHashSet集合中的元素添加到List集合中
list.addAll(lhs);
}
②. 没有带索引的方法,所以不能使用普通for循环遍历
③. 由于是Set集合,所以不包含重复元素的集合
④. 向TreeSet添加属性,需要添加同一类型的属性
①. TreeSet类的add()方法中会把存入的对象提升为Comparable类型
②. 调用对象的CompableTo()方法和集合中的对象比较
③. 根据CompableTo()方法返回的结果进行储存
④. TreeSet底层是一个二叉树,两个叉。小的存储在左边(负数),大的存储在右边(正数),相等就不存0。CompareTo方法,在TreeSet集合如何存储元素取决于compareTo方法的返回值
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Person> ts=Sets.newTreeSet();
ts.add(new Person("张三",23));
ts.add(new Person("李四",13));
ts.add(new Person("唐志",13));
ts.add(new Person("王五",43));
ts.add(new Person("赵六",33));
//[Person(name=李四, age=13), Person(name=张三, age=23), Person(name=赵六, age=33), Person(name=王五, age=43)]
System.out.println(ts);
}
}
@Data
@AllArgsConstructor
class Person implements Comparable{
private String name;
private Integer age;
//按照年龄从小到大排序
public int compareTo(Object o) {
Person p=(Person)o;
int num=this.age-p.age;//年龄是比较的主要条件
//int num=-this.age-p.age;//年龄从大到小排序
return num==0?this.name.compareTo(p.name):num;//姓名是比较的次要条件
}
}
public class TreeSetDemo {
public static void main(String[] args) {
TreeSet<Person> ts=Sets.newTreeSet();
ts.add(new Person("张三",23));
ts.add(new Person("李四",13));
ts.add(new Person("李四",12));
ts.add(new Person("王五",43));
ts.add(new Person("赵六",33));
System.out.println('张'+0);//24352
System.out.println('李'+0);//26446
System.out.println('王'+0);//29579
System.out.println('赵'+0);//36213
//[Person(name=张三, age=23), Person(name=李四, age=12), Person(name=李四, age=13), Person(name=王五, age=43), Person(name=赵六, age=33)]
System.out.println(ts);
}
}
@Data
@AllArgsConstructor
class Person implements Comparable{
private String name;
private Integer age;
//按照姓名进行排序,相同按照年龄进行排序
public int compareTo(Object o) {
Person p=(Person)o;
int num=this.name.compareTo(p.name);
return num==0?this.age-p.age:num;
}
}
①. 创建TreeSet的时候可以制定一个Comparator接口
②. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
③. 调用的对象是Comparator接口中compare()方法顺序
④. 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
@Test
public void fun4(){
/*
需求:将字符串按照长度排序
* */
//Comparator c=new CompareByLen();
//new TreeSet(Comparator );
TreeSet<String>ts=new TreeSet<>(new CompareByLen());
ts.add("aaaaaaaa");
ts.add("z");
ts.add("wc");
ts.add("nba");
ts.add("cba");
System.out.println(ts);//[n, bb, aaa]
}
class CompareByLen /* extends Object*/implements Comparator<String>{//
@Override
public int compare(String s1, String s2) {
//按照字符串长度进行比较
int num=s1.length()-s2.length();//长度为主要条件
return num==0?s1.compareTo(s2):num;//内容为次要条件
}
}
//java.lang.ClassCastException: com.itheima.TreeSetDemo4.Person cannot be cast to java.base/java.lang.Comparable
public class Person {
private String name;
private int age;
public Person(){}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
@Test
public void fun1(){
//1.按照年龄来排序
TreeSet<Person>ts=new TreeSet<>();
ts.add(new Person("张三",23));
ts.add(new Person("张三",23));
ts.add(new Person("张三",23));
ts.add(new Person("李四",24));
ts.add(new Person("王五",24));
System.out.println("ts = " + ts);
}