今日总结
Set集合
HashSet
- LinkedHashSet
- TreeSet
- 泛型
- 可变参数
1 Set集合
1.1 体系
Collection
List
- ArrayList
- LinkedList
Set:存取无序,没有索引,不能存储重复元素
HashSet
- LinkedHashSet
- 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<int> ---> ArrayList<Integer> ArrayList<double> ---> ArrayList<Double>
泛型定义格式
- <类型>:指定一种类型的格式。这里的类型可以看成是形参
- <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
<E> <K,V> <K,V,...>
泛型的好处
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换,简化了代码
4.2 泛型类
在类名后面加上泛型
定义格式
修饰符 class 类名<类型> { }
示例代码
public class Generic<T> { private T t; public T getT() { return t; } public void setT(T t) { this.t = t; } }
4.3 泛型方法
在方法的声明上定义泛型
定义格式
修饰符 <类型> 返回值类型 方法名(类型 变量名) { }
示例代码
public class Generic { public <T> void show(T t) { System.out.println(t); } }
4.4 泛型接口
定义格式
修饰符 interface 接口名<类型> { }
示例代码
泛型接口
public interface Generic<T> { void show(T t); }
泛型接口实现类
public class GenericImpl<T> implements Generic<T> { @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、数组位置灵活
可变参数的位置只能在方法的小括号中,当做形参使用