Set
java.util.Set接口 extends Collection接口
Set接口的特点:不允许存储重复的元素,没有索引,没有带索引的方法,也不能使用普通的for循环进行遍历
java.util.HashSet集合,implements Set接口
HashSet特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3、是一个无序的集合,存储元素和取出元素的顺序可能不一致
4、底层是一个哈希表结构(查询的速度非常的快)
public class Demo1Set {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
//使用add方法往集合中添加元素
set.add(1);
set.add(3);
set.add(2);
set.add(1);
//使用迭代器遍历set集合
Iterator<Integer> it = set.iterator();
while(it.hasNext()){
Integer n = it.next();
System.out.println(n);//123 重复的1没有存进去,顺序也不一样
}
//使用增强for循环
for (Integer i : set) {
System.out.println(i);//123
}
}
}
哈希表
JDK1.8之前,底层使用数组+链表组成,JDK1.8之后,底层采用数组+链表+红黑树组成。
哈希值
哈希值是JDK根据对象的地址,按照某种规则算出来的int类型的数值。
同一个对象多次调用hashCode()方法返回的哈希值是相同的,默认情况下,不同对象的哈希值是不同的。
哈希值:是一个10进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到的地址,不是数据实际存储的地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode() 返回该对象的哈希码值
hashCode方法的源码:
public native int hashCode();
native:代表该方法调用的是本地操作系统的方法
public class Demo01HashCode {
public static void main(String[] args) {
//Person类继承了Object类,所以可以使用Object类hashCode方法
Person p1 = new Person();
int h1 = p1.hashCode();
System.out.println(h1);//189568618
Person p2 = new Person();
int h2 = p2.hashCode();
System.out.println(h2);//793589513
//String类的哈希值 String类重写了Object类的hashCode方法
String s1 = new String("abc");
String s2 = new String("abc");
System.out.println(s1.hashCode());//96354
System.out.println(s2.hashCode());//96354
System.out.println("重地".hashCode());//1179395
System.out.println("通话".hashCode());//1179395
}
}
HashSet集合存储数据的结构
Set集合不允许重复元素的原理
public class Demo02HashSetSaveString {
public static void main(String[] args) {
//创建HashSet集合对象
HashSet<String> set = new HashSet<>();
String s1 = new String("abc");
String s2 = new String("abc");
set.add(s1);
set.add(s2);
set.add("重地");
set.add("通话");
set.add("abc");
System.out.println(set);//[重地, 通话, abc]
}
}
HashSet存储自定义类型元素
在给HashSet中存放自定义类型元素时,需要重写对象中的hashCode和equals方法,建立自己的比较方式,才能保证HashSet集合中的对象唯一
HashSet存储自定义类型元素
Set集合保存元素唯一:
存储的元素(String,Integer,…Student,Person…),必须重写hashCode和equals方法
要求:
同名和同年龄的人,视为同一个人,只能存储一次
重写hashCode和equals方法之前
重写hashCode和equals方法之后
主方法
public class Demo03HashSetSavePerson {
public static void main(String[] args) {
//创建一个HashSet集合存储Person
HashSet<Demo03Person> set = new HashSet<>();
Demo03Person p1 = new Demo03Person("刘辣子",18);
Demo03Person p2 = new Demo03Person("刘辣子",18);
Demo03Person p3 = new Demo03Person("刘辣子",19);
set.add(p1);
set.add(p2);
set.add(p3);
System.out.println(set);
}
}
Person类
import java.util.Objects;
public class Demo03Person {
private String name;
private int age;
public Demo03Person() {
}
public Demo03Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Demo03Person that = (Demo03Person) o;
return age == that.age && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Demo03Person{" +
"name='" + name + '\'' +
", 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;
}
}
LinkedHashSet
java.util.LinkedHashSet集合 extends HashSet 集合
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一层链表(记录元素的存储顺序),可以保证元素有序
public class Demo04LinkHashSet {
public static void main(String[] args) {
HashSet<String> set = new HashSet<>();
set.add("zgDaren");
set.add("abc");
set.add("abc");
set.add("com");
System.out.println(set);//[com, abc, zgDaren]无序,不允许重复
LinkedHashSet<String> linked = new LinkedHashSet();
linked.add("zgDaren");
linked.add("abc");
linked.add("abc");
linked.add("com");
System.out.println(linked);//[zgDaren, abc, com]有序,不允许重复
}
}
TreeSet集合概述和特点
不重复、无索引、可排序
可排序:按照元素的大小默认升序(从大到小)排序
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都比较好。
TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序
TreeSet集合默认的规则
对于数值类型:Integer,Double,官方默认按照大小进行升序排序
对于字符串类型:默认按照首字符的编号升序排序
对于自定义类型如student对象,TreeSet无法直接排序。
TreeSet自定义排序规则
1、让自定义的类(如学生类)实现Comparable接口重谢里面的compareTo方法来定制比较规则。
2、TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则。
两种方式中,关于返回值的规则:
如果认为第一个元素大于第二个元素返回正整数即可。
如果认为第一个元素小于第二个元素返回负整数即可。
如果认为第一个元素等于第二个元素返回0即可,此时TreeSet集合只会保留一个元素,认为两者重复。
注意:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。
1、如果希望元素可以重复,又有索引,索引查询要快
使用ArrayList集合,基于数组的。(用的最多)
2、如果希望元素可以重复,又有索引,增删首尾操作快?
用Linkedlist集合,基于链表的。
3、如果希望增删改查都快,但是元素不重复、无序、无索引
用HashSet集合,基于哈希表的
4、如果希望增删改查都快,但是元素不重复、有序、无索引
用LinkedHasdSet集合,基于哈希表和双链表
5、如果要对对象进行排序
用TreeSet集合,基于红黑树,后续也可以用List集合实现排序。
可变参数
可变参数:是JDK1.5之后出现的新特性
使用前提:
当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符 返回值类型 方法名 (数据类型…变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递的参数个数,可以是0个(不传递),1,2,3…多个
可变参数的注意事项
1、一个方法的参数列表,只能有一个可变参数,数据类型不同也不行
2、如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
public class DemoVarArgs {
public static void main(String[] args) {
//int i = add();不传参数
//int i = add(10);一个参数
int i = add(10,23,45,66,43,22,56,322,1123);//1710
System.out.println(i);
method("abc",8.8,3,12,34,5456);
}
//只能有一个可变参数,数据类型不同也不行
//public static void method(int...a,String...b){}
//如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
public static void method(String b,double c,int d,int...a){
}
//可变参数的特殊写法(终极)写法
public static void method1(Object...obj){//Object可以接收任意类型的参数
return;
}
//定义计算(0~n)个整数和的方法
//已知:计算整数的和,数据类型已经确定int
//但是参数的个数不确定,不知道要计算几个整数的和,就可以使用可变参数
//add();就会创建一个长度为0的数组,new int[0]
//add(10);就会创建一个长度为1的数组,存储传递过来的参数 new int []{10}
add(10,20);就会创建一个长度为1的数组,存储传递过来的参数 new int []{10,20}
public static int add(int...arr){
System.out.println(arr);//底层是一个数组,[I@10f87f48
System.out.println(arr.length);//0,长度为0的数组,如果是一个参数长度就为1,两个为2...
//定义一个初始化的变量,记录累加求和
int sum = 0;
//遍历数组,获取数组中的每一个元素
for (int i : arr){
sum += i;//累加求和
}
//把求和结果返回
return sum;
}
/* //定义一个方法,计算三个int类型整数的和
public static int add(int a,int b,int c){
return a+b+c;
}
//定义一个方法,计算两个int类型整数的和
public static int add(int a,int b){
return a+b;
}*/
}
java.util.Collection是集合工具类,用来对集合进行操作
public static boolean addAll(Collection c, T…elements):往集合中添加一些元素
public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序
public class Demo01Collections {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
//往集合中添加多个元素
list.add("a");
list.add("b");
list.add("c");
list.add("d");
list.add("e");
System.out.println(list);//[a, b, c, d, e]
//public static <T> boolean addAll(Collection<T> c, T...elements):往集合中添加一些元素
ArrayList<String> list1 = new ArrayList<>();
Collections.addAll(list1,"a","b","c","d","e");
System.out.println(list1);//[a, b, c, d, e]
//public static void shuffle(List<?> list) 打乱顺序:打乱集合顺序
Collections.shuffle(list);
System.out.println(list);//[e, a, c, d, b]
}
}
public static void sort(List list):将集合中的元素按照默认规则排序
注意:该方法的使用中,被排序的集合里边存储元素,必须实现Comparable,重写接口中的方法compereTo定义排序的规则
Comparable接口的排序规则
自己(this)- 参数 升序
public class Demo02Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
//public static <T> void sort(List<T> list):将集合中的元素按照默认规则排序
//静态方法可以直接使用类名来使用
//参数只能传递list集合,不能传递set集合
Collections.sort(list01);//默认为升序
System.out.println(list01);//[1, 2, 3]
ArrayList<String> list02 = new ArrayList<>();
list02.add("a");
list02.add("c");
list02.add("b");
System.out.println(list02);//[a, c, b]
Collections.sort(list02);
System.out.println(list02);//[a, b, c]
//使用自定义类
ArrayList<Person> list03 = new ArrayList<>();
list03.add(new Person("张三",18));
list03.add(new Person("李四",28));
list03.add(new Person("王五",19));
System.out.println(list03);//[Person{name='张三', age=18}, Person{name='李四', age=28}, Person{name='王五', age=19}]
Collections.sort(list03);
System.out.println(list03);//[Person{name='张三', age=18}, Person{name='王五', age=19}, Person{name='李四', age=28}]
}
}
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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 int compareTo(Person o) {
//return 0;//返回0是因为认为元素是相同的
//定义比较的规则,比较两个人的年龄(this,参数Person)
return this.getAge() - o.getAge();//升序排序年龄
//return o.getAge() - this.getAge();//降序排序年龄
}
}
java.utils.Collections集合工具类,用来对集合进行操作
public static void (list list,Comparator< ? super T>):将集合中元素按照指定规则排序)
Comparator和Comparable的区别
Comparable:自己(this)和别人(参数)比较,自己需要实现ComParable接口,重写比较的规则compareTo
Comparator:相当于找也给第三方的裁判,比较两个
Comparator的排序规则o1 - o2升序,o2 - o1;降序
public class Demo03Sort {
public static void main(String[] args) {
ArrayList<Integer> list01 = new ArrayList<>();
list01.add(1);
list01.add(3);
list01.add(2);
System.out.println(list01);//[1, 3, 2]
Collections.sort(list01, new Comparator<Integer>() {
//重写比较的规则
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;//升序
//return o2 - o1;//降序
}
});
System.out.println(list01);//[1, 2, 3]
//使用自定义类
ArrayList<Student> list02 = new ArrayList<>();
list02.add(new Student("张三",18));
list02.add(new Student("李四",28));
list02.add(new Student("王五",19));
System.out.println(list02);//[Student{name='张三', age=18}, Student{name='李四', age=28}, Student{name='王五', age=19}]
Collections.sort(list02, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排序
return o1.getAge() - o2.getAge();
}
});
System.out.println(list02);//[Student{name='张三', age=18}, Student{name='王五', age=19}, Student{name='李四', age=28}]
//使用自定义类
ArrayList<Student> list03 = new ArrayList<>();
list03.add(new Student("a张三",18));
list03.add(new Student("李四",28));
list03.add(new Student("王五",19));
list03.add(new Student("b王五",18));
System.out.println(list03);
Collections.sort(list03, new Comparator<Student>() {
@Override
public int compare(Student o1, Student o2) {
//按照年龄升序排序
int result = o1.getAge() - o2.getAge();
//如果两个人年龄想相同,在使用姓名的第一个字比较
if (result==0){
result = o1.getName().charAt(0) - o2.getName().charAt(0);
}
return result;
}
});
System.out.println(list03);//按照年龄排序,如果有年龄相同,姓名不同,则哪个在前面哪个就先输出
}
}
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", 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;
}
}