Set集合
HashSet集合
HashSet集合保证元素唯一性的原理
HashSet底层数据结构是哈希表结构,当往HashSet集合中存储元素的时候
1.会计算元素的hashCode值,如果集合中已经有相同的hashCode值那么还会判断元素的equals是否相同
2.如果元素的equals比较也相同,那么就认为元素重复;否则就不重复。
HashSet存储自定义的元素
如果往HashSet集合中存储自定义的对象,为了保证元素的唯一性,我们可以复写hashCode和equals方法
public class Student {
private String name;
private int age;
//构造法方法、get和set方法,此处省略(需要的话自己补充)
//复写hashCode方法,让hashCode值和对象的属性值产生关联;只要属性值一样,hashCode值就一样
@Override
public int hashCode() {
return Objects.hash(name, age);
}
//复写equals方法,让equals方法的比较方式也和属性值产生关联;只要属性值一样,equals比较结果就相同
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age &&
Objects.equals(name, student.name);
}
}
LinkedHashSet
LinkedHashSet底层数据结构是:链表+哈希表,可以保证元素的迭代顺序
【HashSet和LinkedHashSet,除了迭代顺序不一样,其他的特点都是一样的】
TreeSet集合
TreeSet集合可以对集合中的元素进行排序(可以是自然排序也可以是自定义排序),也可以保证元素唯一.
自然排序
1.元素实现Comparable接口
2.复写compareTo方法,通过该方法的返回值是正数、负数、或者0来判断元素是大、小、还是相等
正数:我们添加的元素比集合中已有的元素大
负数:我们添加的元素比集合中已有的元素小
零 : 我们添加的元素和集合中已有的元素相等(不存储该元素)
public class Student implements Comparable {
private String name;
private int age;
//此处省略了构造方法、get和set方法、以及toString方法
@Override
public int compareTo(Student o) {
//按照学生的年龄进行排序
int num= this.age-o.age;
//如果年龄相同,就按照姓名的升序进行排列
if(num==0){
num=this.name.compareTo(o.name);
}
return num;
}
}
public class Demo3 {
public static void main(String[] args) {
TreeSet ts2=new TreeSet<>();
ts2.add(new Student(“xiaoming”,20));
ts2.add(new Student(“xiaoqiang”,30));
ts2.add(new Student(“xiaohuang”,28));
ts2.add(new Student(“xiaobai”,28));
for (Student stu : ts2) {
System.out.println(stu);
}
}
}
比较器排序
1.写一个Comparator接口的实现类
2.复写compare方法,通过该方法的返回值是正数、负数、或者0来判断元素是大、小、还是相等
正数:我们添加的元素比集合中已有的元素大
负数:我们添加的元素比集合中已有的元素小
零 : 我们添加的元素和集合中已有的元素相等(不存储该元素)
3.Comparator接口的实现类对象,当做TreeSet构造方法的参数
4.再往TreeSet集合中添加对象,该集合就可以对元素进行排序
//1.写一个Comparator接口的实现类
//2.复写compare方法,通过该方法的返回值是正数、负数、或者0来判断元素是大、小、还是相等
public class MyComparator implements Comparator {
@Override
public int compare(Student o1, Student o2) {
//首先按照学生的年龄升序进行排序
int num=o1.getAge()-o2.getAge();
//如果年龄相同,就按照姓名进行排序
if(num0){
num=o1.getName().compareTo(o2.getName());
}
return num;
}
}
public class Demo3 {
public static void main(String[] args) {
//3.Comparator接口的实现类对象,当做TreeSet构造方法的参数
//TreeSet ts=new TreeSet<>(new MyComparator());
TreeSet ts=new TreeSet<>(new Comparator() {
@Override
public int compare(Student o1, Student o2) {
//首先按照学生的年龄升序进行排序
int num=o1.getAge()-o2.getAge();
//如果年龄相同,就按照姓名进行排序
if(num0){
num=o1.getName().compareTo(o2.getName());
}
return num;
}
});
//4.再往TreeSet集合中添加对象,该集合就可以对元素进行排序
ts.add(new Student("xiaoming",18));
ts.add(new Student("xiaoqing",20));
ts.add(new Student("xiaoxing",19));
ts.add(new Student("xiaoding",18));
for (Student t : ts) {
System.out.println(t);
}
}
}
泛型
泛型表示一个不确定的数据类型,使用<字母>表示,比、<W,R>
泛型的好处
1.把运行时期的错误转移到了编译时期
- 在运行时有可能产生类型转换的异常
2.避免了强制转换的麻烦 - 使用泛型之后类型就统一了,自然就不会有类型转换
泛型类
//在类名后面写上一个<字母>,表示在类中有不确定的数据类型
public class GenericClass{
private T name;
public T getName(){
retur name;
}
public void setName(T name){
this.name=name;
}
}
//在创建对象的时候,来确定类上的泛型
public class GenericDemo1{
public static void main(String[] args){
//指定GenericClass类中的为String类型
GenericClass gc=new GenericClass();
gc.setName(“小明”);
String name=gc.getName();
System.out.println(name); //小明
System.out.println("----------");
//指定GenericClass类中的<T>为Integer类型
GenericClass<Integer> gc=new GenericClass<Integer>();
gc.setName(100);
Intger name=gc.getName();
System.out.println(name); //100
}
}
泛型方法
//在定义方法的时候,在返回值类型和修饰符之间写一个<字母>,表示在方法中有一个不明确的数据类型
public void method(T t){
…
}
//调用泛型方法,通过实际参数来明确具体是什么类型
method(“hello”);
method(100);
method(true);
泛型接口
//在定义接口时,在接口名的后写一个<字母>,表示在接口中一个不明确的数据类型
public interface Inter{
public void method(T t){
…
}
}
//在Inter接口的实现类中来明确的数据类型
public class InterImpl implements Inter{
public void method(String t){
…
}
}
//把Inter接口中的泛型,沿用到实现类中,在创建实现类对象时来明确的实际类型
public class InterImpl implements Inter{
public void method(T t){
…
}
}
类型通配符
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
}
//参数是List集合,集合中元素可必须是Number或者Number的子类
public static void method2(List<? extends Number> list){
for (int i = 0; i < list.size(); i++) {
Number number = list.get(i);
System.out.println(number);
}
}
//参数是List集合,集合中元素可必须是Number或者Number的父类
public static void method3(List<? super Number> list){
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
}
可变参数
//可变参数:多个同类型的参数,本质上就是一个数组
//格式: 数据类型…变量名
public static int getSum(int…arr){
int sum=0;
for (int i = 0; i < arr.length; i++) {
sum+=arr[i];
}
return sum;
}
public static void main(String[] args) {
int sum = getSum(3, 4);
System.out.println(sum); //7
int sum1 = getSum(3, 4, 5,113,40,5,5,6,6);
System.out.println(sum1); //12
int[] array={1,2,3,4,5,6};
int sum2 = getSum(array);
System.out.println(sum2);
}