今日总结Set集合HashSetLinkedHashSet
TreeSet
泛型
可变参数
1 Set集合
1.1 体系
CollectionListArrayList
LinkedList
Set:存取无序,没有索引,不能存储重复元素HashSetLinkedHashSet
TreeSet
Set接口中没有特有方法,其中和Collection完全相同
1.2 哈希值哈希值
是 JDK 根据对象的地址或者字符串或者数字算出来的 int 类型的数值
如何获取哈希值
Object 类中的 public int hashCode():返回对象的哈希码值
哈希值的特点同一个对象多次调用 hashCode() 方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。而重写 hashCode() 方法,可以实现让不同对象的哈希值相同。
1.3 HashSet集合HashSet 集合的特点底层数据结构是哈希表
对集合的迭代顺序不作任何保证,也就是说不保证存储和取出的元素顺序一致
没有带索引的方法,所以不能使用普通 for 循环遍历
由于是 Set 集合,所以是不包含重复元素的集合
1.4 HashSet集合保证元素唯一性源码分析HashSet集合保证元素唯一性的原理
1.根据对象的哈希值计算存储位置
如果当前位置没有元素则直接存入
如果当前位置有元素存在,则进入第二步
2.当前元素的元素和已经存在的元素比较哈希值
如果哈希值不同,则将当前元素进行存储
如果哈希值相同,则进入第三步
3.通过equals()方法比较两个元素的内容
如果内容不相同,则将当前元素进行存储
如果内容相同,则不存储当前元素
HashSet如果存储JDK提供的一些类型的对象(比如:String)不需要去重写hashCode和equals方法,因为JDK已经实现了,所以直接存储就能做到去重。
如果存储一些自定义类型的对象(比如:Student)就需要去重写hashCode和equals方法,重写之后才能保证去重。
如何重写这两个方法:快捷键 alt+insert 选择 hashCode & equals 即可
HashSet集合保证元素唯一性的图解
1.5 常见数据结构之哈希表
1.6 LinkedHashSet集合LinkedHashSet 集合特点底层的数据结构:双向链表+哈希表(数组+链表),具有可预测的迭代次序
由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
由哈希表保证元素唯一,也就是说没有重复的元素
2 Set集合排序
2.1 TreeSet集合概述和特点TreeSet集合概述元素有序,可以按照一定的规则进行排序,具体排序方式取决于构造方法TreeSet():根据其元素的自然排序进行排序
TreeSet(Comparator comparator) :根据指定的比较器进行排序
没有带索引的方法,所以不能使用普通 for 循环遍历
由于是 Set 集合,所以不包含重复元素的集合
两种排序方式:
1、自然排序
元素所在的类要实现 Comparable 接口,重写 compareTo 方法
重写compareTo方法
(1)参数
this:即将添加进行排序的元素
o:集合中已经排好的元素
this - o:升序
o - this:降序
(2)返回值
正数:将元素放右边,返回值固定是正数,升序
0:重复元素,去除
负数:将元素放左边,返回值固定是负数,降序
2、比较器排序
在TreeSet的构造方法中传递一个Comparator的实现类对象,重写compare方法
重写compareTo方法
(1)参数
s1:即将添加进行排序的元素,相当于之前的this
s2:集合中已经排好的元素,相当于之前的o
s1 - s2:升序
s2 - s1:降序
(2)返回值
正数:将元素放右边,返回值固定是正数,升序
0:重复元素,去除
负数:将元素放左边,返回值固定是负数,降序
PS:两种比较方式可以达到一模一样的效果,两种可以随意选择一个。
而且这两种比较方式可以同时存在,它会优先选择比较器排序。
3 如何选择集合?能存储重复元素选择List集合,优先ArrayList
只有当增删多的时候,可以选择LinkedList,否则都选择ArrayList
不能存储重复元素选择Set集合,优先选择HashSet
如果需要保证存取有序,可以选择LinkedHashSet
如果需要保证元素存完之后可以排序,可以选择TreeSet
4 泛型
4.1 泛型概述和好处泛型概述
泛型是JDK5中引入的新特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型;
泛型是一种广泛的类型,可以它是一个变量,你想让它是什么类型它就是什么类型;
泛型中传递的类型只能是引用数据类型,不能是基本数据类型。ArrayList ---> ArrayList
ArrayList ---> ArrayList
泛型定义格式:指定一种类型的格式。这里的类型可以看成是形参
:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
泛型的好处把运行时期的问题提前到了编译期间
避免了强制类型转换,简化了代码
4.2 泛型类
在类名后面加上泛型定义格式修饰符 class 类名 { }
示例代码public class Generic {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
4.3 泛型方法
在方法的声明上定义泛型定义格式修饰符 返回值类型 方法名(类型 变量名) { }
示例代码public class Generic {
public void show(T t) {
System.out.println(t);
}
}
4.4 泛型接口定义格式修饰符 interface 接口名 { }
示例代码泛型接口public interface Generic {
void show(T t);
}
泛型接口实现类public class GenericImpl implements Generic {
@Override
public void show(T t) {
System.out.println(t);
}
}
4.5 类型通配符类型通配符的作用
为了表示各种泛型List的父类,可以使用类型通配符
类型通配符的分类类型通配符:>List>:表示元素类型未知的List,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
类型通配符上限: extends 类型>List extends Number>:它表示的类型是Number或者其子类型
类型通配符下限: super 类型>List super Number>:它表示的类型是Number或者其父类型
5 可变参数JDK1.5的新特性(自动拆装箱、增强for、泛型、可变参数)可变参数又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
可变参数只能在方法的小括号中(在形式参数位置)使用
格式:数据类型... 变量名
String... strs
int... arr
Student... arr
修饰符 返回值类型 方法名(数据类型... 变量名){
方法体;
}
注意事项:
1、 可变参数的本质是数组
2、可变参数传递的实参可以是0~无穷多个
可以传递数组,也可以将数组中的元素拿出来进行传递
3、如果一个方法的参数包含可变参数,且参数个数有多个,
这时可变参数必须位于最后一位,所以一个方法的可变参数只能有一个数组和可变参数的区别
1、形参是数组类型,实参可能传递数组
形参是可变参数类型,实参可以传递数组也可以单独传递数组中的元素
2、形参是数组类型,实参不能不传递
形参是可变参数类型,实参可以不传递(0个实参)
3、数组位置灵活
可变参数的位置只能在方法的小括号中,当做形参使用