Java基础(十七)——Set集合、可变参数和Collections工具类
Set接口
java.util.set接口和java.util.List接口是一样的,都是继承自Collection接口,它与collection接口中的方法基本一样,没有对Collection接口进行功能上的扩展,只是比Collection接口更加严格。与List接口不同的是,Set接口中的元素是无序的,并且都会以某种规则保证存入的元素不重复。
Set集合取出元素的方式可以采用:迭代器、增强for循环。
HashSet集合介绍
java.util.HashSet是Set接口的一个实现类,它存储的元素是不可重复的,并且元素都是无序的(存取顺序不一致)。java.util.HashSet底层的实现其实是一个java.util.HashMap支持的。
HashSet是根据对象的哈希值来确定元素在集合当中的存储位置,因此它具有良好的存取和查找性能。保证元素唯一性的方式依赖于hashCode和equals方法。
实例代码:
1 //创建HashSet集合对象 2 HashSet<String> hashSet = new HashSet<>(); 3 String str01 = new String("abc"); 4 String str02 = new String("abc"); 5 hashSet.add(str01); 6 hashSet.add(str02); 7 hashSet.add("种地"); 8 hashSet.add("通话"); 9 hashSet.add("abc"); 10 System.out.println(hashSet);//[通话, abc, 种地] 11 //依赖于hashCode和equals方法 12
HashSet集合存储数据的结构(哈希表)
什么是哈希表呢?
在JDK1.8之前,哈希表的底层采用的是数组+链表实现,即使用链表处理哈希冲突,同一哈希值的链表都存储在一个链表里,但是当位于一个链中的元素较多时,即hash值相等的元素较多时,通过key值依次查找的效率很低下。在JDK1.8中,哈希表存储结构采用数组+链表/红黑树实现的,当链表的长度超过阈值(8)时,将链表转换成红黑树结构,这样的好处是大大减少了查找的时间。
如图展示:
总而言之,JDK1.8之后引入红黑树结构大大优化了HashMap的性能,那么对于我们来讲保证HashSet元素唯一不重复,其实是根据对象的hashCode和equals方法来决定的。如果我们往集合当中存储的是自定义的对象,需要保证对象的唯一性,就必须重写hashCode和equals方法,来自定义当前的对象的比较方式。
HashSet保证元素唯一的原理,如图所示
HashSet存储自定义类型的元素
一般需要重写对象当中的hashCode和equals方法,建立自己的比较方式。才能保证HashSet集合中元素的唯一性。
代码示例:
1 @Override 2 public boolean equals(Object o) { 3 if (o == null) { 4 return false; 5 } 6 if (this == o) { 7 return true; 8 } 9 // 向下转型 类型判断 10 if (o instanceof Student) { 11 Student student = (Student)o; 12 // 同名同年龄的人为同一个人 true 13 return student.getName().equals(name) && student.getAge() == age; 14 } 15 return false; 16 } 17 18 @Override 19 public int hashCode(){ 20 // 使用Objects类中的hash方法 21 return Objects.hash(name,age); 22 }
LinkedHashSet集合
我们知道HashSet保证元素的唯一,可是存进去的元素是没有顺序的,那么如何保证存进去的元素是有序的?
在java.util.HashSet类的下面还有一个子类java.util.LinkedHashSet,它是链表和哈希表的组合的一个数据存储结构。代码示例:
1 // 构建一个LinkedHashSet集合对象 2 LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>(); 3 linkedHashSet.add("www"); 4 linkedHashSet.add("baidu"); 5 linkedHashSet.add("com"); 6 linkedHashSet.add("abc"); 7 linkedHashSet.add("abc"); 8 linkedHashSet.add("java"); 9 linkedHashSet.add("python"); 10 // [www, baidu, com, abc, java, python] 11 System.out.println(linkedHashSet);// [www, baidu, com, abc] 有序的,不重复的
可变参数
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数的数据类型一致,那么我们可以简化成如下格式:
1 修饰符 返回值类型 方法名(参数类型... 形参名){ 2 //... 3 }
其实上面的格式完全等价于:
1 修饰符 返回值类型 方法名(参数类型[] 参数名){ 2 //.... 3 }
只是后面的写法,在方法调用,必须传递一个数组类型,而前者可以直接传递参数数据。
JDK1.5之后,出现的这种简化操作。"..."用在参数上,我们称之为可变参数。
同样是代表数组,但是在方法调用这个带有可变参数时,不用创建数组,而是直接将数组当中的元素作为实际参数进行传递,其实编译生成的.class文件,本质是将这些元素封装到了一个数组当中,再进行数据传递,这些动作都在编译生成.class文件的时候,自动完成了。
代码示例:
1 public static void add(int... arr) { 2 //System.out.println(arr);// [I@1b6d3586 底层就是一个数组 3 //System.out.println(arr.length);//0 4 int sum = 0; 5 for (int i = 0; i < arr.length; i++) { 6 sum += arr[i]; 7 } 8 System.out.println(sum); // 30 9 }
Collections集合工具类
常用功能
public static <T> boolean addAll(Collection<? super T> c,T... elements)
:往集合中一次性添加多个元素。
public static <T> void shuffle(List<?> list)
:打乱集合中的元素顺序。
public static <T> void sort(List<T> list)
:将集合中的元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T> c)
代码演示:
1 ArrayList<String> strs = new ArrayList<>(); 2 //往集合当中存储元素 3 /*strs.add("abc"); 4 strs.add("小孙"); 5 strs.add("小刘"); 6 strs.add("小赵");*/ 7 8 //使用Collections集合工具类中的addAll 9 Collections.addAll(strs, "张三","老王","小金豆","孬蛋","老白干"); 10 System.out.println(strs); 11 System.out.println("========================="); 12 Collections.shuffle(strs); 13 System.out.println(strs);
1 ArrayList<Integer> list01 = new ArrayList<>(); 2 Collections.addAll(list01, 124,234,566,324,765,342); 3 System.out.println(list01); 4 System.out.println("============================"); 5 Collections.sort(list01); 6 System.out.println(list01); 7 System.out.println("============================"); 8 ArrayList<String> list02 = new ArrayList<>(); 9 Collections.addAll(list02,"asd","sd","sc","sv","ac","b","vc","v","cs"); 10 Collections.shuffle(list02); 11 Collections.sort(list02); 12 System.out.println(list02);