概述
- java.util.Set接口 extends Collection接口
- Set接口的特点
1) 不允许存储重复的元素
2)没有索引,没有带索引的方法,也不能使用普通的for循环遍历;
HashSet集合
- java.util.HashSet集合 implements Set接口
- HashSet特点:
1)不允许存储重复的元素
2)没有索引,也没有带索引的方法,也不能使用普通的for循环遍历(可以使用迭代器和增强for循环遍历)
3)是一个无序的集合,存储元素和取出元素的顺序有可能不一致;
4)底层是一个哈希表结构(查询的速度非常快)
哈希值
- 是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来的地址,不是数据实际存储的物理地址)
- 在Object类有一个方法,可以获取对象的哈希值;
- int hashCode():返回该对象的哈希码值;
hashCode()的源码:public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
public class HashCode {
public static void main(String[] args) {
HashCode hc1=new HashCode();
int h1=hc1.hashCode();
System.out.println(h1);//460141958
HashCode hc2=new HashCode();
int h2=hc2.hashCode();
System.out.println(h2);//1163157884
/*
toString()的源码:其实也是调用了hashcode()方法
return getClass().getName() + "@" + Integer.toHexString(hashCode());
*/
System.out.println(hc1.toString());//HashCode@1b6d3586(460141958的十六进制)
System.out.println(hc2.toString());//HashCode@4554617c(1163157884的十六进制)
/*
String类的哈希值
String类重写了Object类的hashCode()方法,直接返回十进制hash值
*/
String s1=new String("abc");
String s2=new String("bcd");
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//97347
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
}
}
哈希表结构
Set集合不允许存储重复元素的原理
![不存储重复元素原理](https://i-blog.csdnimg.cn/blog_migrate/451112fc402adcdd93f8622e59f72ac6.png)
HashSet存储自定义类型元素
- 给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一 ;
//同名同年龄的人是同一个人
public class Person {
private String name;
private int age;
public Person(String name,int age){
this.age=age;
this.name=name;
}
@Override
public int hashCode() {
return Objects.hash(name,age);
}
@Override
public boolean equals(Object obj) {
if(this == obj)
return true;
if(obj == null || getClass() != obj.getClass())
return false;
//向下转型
Person p=(Person)obj;
return this.age==p.age && Objects.equals(this.name,p.name);
}
public static void main(String[] args) {
//同名同年龄的人是同一个人,若不重写hashcode方法得到的是两个不同的hash值
Person p1=new Person("gg",20);
Person p2=new Person("gg",20);
System.out.println(p1.hashCode());//103157
System.out.println(p2.hashCode());//103157,哈希值相同
System.out.println(p1.equals(p2));//true,内容相同
System.out.println(p1.equals(p2));//重写了之后比较的是内容,而不是内存中的地址值
System.out.println(p1 == p2);//false,p1在内存中的地址值和p2不一样(即使逻辑地址hash值一样)
}
LinkedHashSet集合
- java.util.LinkedHashSet集合 extens HashSet集合
- 特点:
1)底层是一个哈希表+链表:多了一条链表(记录元素的存储顺序),保证元素有序;
2)有序,不重复
可变参数
- 可变参数:是JDK1.5之后出现的新特性
- 使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定时,就可以使用可变参数;
- 使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型…变量名){}(注意:三个点) - 可变参数的原理
可变参数的底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数; - 可变参数注意事项:
1)一个方法的参数列表,只能有一个可变参数
2)如果方法的参数有多个,那么可变参数必须写在参数列表的末尾;
public class KeBianCanShu {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3};
add(arr);//一种方式传入数组
add(10,20,30);//另一种方式,直接传入多个参数
}
//可变参数示例
public static void add(int... arr){
for(int i:arr)
System.out.println(i);
}
//可变参数注意事项
public static void method(int... arr,String... arrS){}//报错,一个方法的参数列表中只能有一个可变参数
public static void method1(int... arr,String s,double d){};//报错,可变参数只能放在参数列表末尾
}
public static void method2(Object... obj){}//可以接收任意类型的数据