一、泛型
泛型是JDK5引入的特性,可以在编译阶段约束操作的数据类型,并进行检查
- 泛型的好处
- 把运行时期的问题提前到了编译期间
- 避免了强制类型转换
- 泛型的定义格式
- <类型>: 指定一种类型的格式.尖括号里面可以任意书写,一般只写一个字母.例如:
- <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开.例如: <E,T> <K,V>
弊端:
利用泛型方法有一个小弊端,此时它可以接受任意的数据类型
通配符
? 也表示不确定的类型, 它可以进行类型的限定
? extends E: 表示可以传递E或者E所有的子类类型
? super E: 表示可以传递E或者E所有的父类类型 E要自己具体定义
应用场景:
1.如果在定义类、方法、接口的时候,如果类型不确定,就可以定义泛型类、泛型方法、泛型接口。
2.如果类型不确定,但是能知道以后只能传递某个继承体系中的,就可以用泛型的通配符
public class GenericsDemo6 {
public static void main(String[] args) {
//泛型不具备继承性,但是数据具备继承性
//创建集合的对象
ArrayList<Ye> list1 = new ArrayList<>();
ArrayList<Fu> list2 = new ArrayList<>();
ArrayList<Zi> list3 = new ArrayList<>();
method(list1);
// method(list2);
list1.add(new Ye());
list1.add(new Fu());
list1.add(new Zi());
}
//此时,泛型里面写的是什么类型,那么只能传递什么类型的数据
public static void method(ArrayList<Ye> list) {
}
}
二、Set
1.HashSet
特点:
- 底层数据结构是哈希表
- 存取无序
- 不可以存储重复元素
- 没有索引,不能使用普通for循环遍历
HashSet添加元素的过程
计算哈希值:调用元素的hashCode()方法,计算出一个int类型的哈希值
计算索引位置:通过哈希值计算在数组中的索引位置 (n - 1) & hash
检查该位置是否有元素
如果该位置为null,直接存入
如果该位置已有元素,调用equals()比较
如果equals返回true,认为是重复元素,不存入
如果equals返回false,以链表或红黑树形式存储(哈希冲突)
由此可以得到输出顺序不一定等于添加顺序
哈希值:对象的整数表现形式
1.如果没有重写hashCode方法,不同对象计算出的哈希值是不同的
//1.创建对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("zhangsan",23);
//2.如果没有重新hashCode方法,不同对象计算出的哈希值是不同的
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());

2.如果已经重写hashCode方法,不同的对象只有属性值相同,计算出的哈希值就是一样的
//在JavaBean类覆盖以下方法,重新运行
@Override
public boolean equals(Object o) {
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}

3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样(哈希碰撞)
System.out.println("abc".hashCode());
System.out.println("acD".hashCode());

总结
- HashSet集合存储自定义类型元素,要想实现元素的唯一,要求必须重写hashCode方法和equals方法
2.LinkedHashSet
该集合的特点及原理
- 有序、不重复、无索引
- 底层基于哈希表,使用双链表记录添加顺序
public class LinkHashSetDemo {
public static void main(String[] args) {
//1.创建三个学生对象
Student s1 = new Student("zhangsan", 23);
Student s2 = new Student("lisi", 24);
Student s3 = new Student("wangwu", 25);
Student s4 = new Student("wangwu", 25);
//保证数据的存取有序
LinkedHashSet<Student> lhs = new LinkedHashSet<>();
System.out.println(lhs.add(s3));
System.out.println(lhs.add(s2));
System.out.println(lhs.add(s1));
System.out.println(lhs.add(s4));
System.out.println(lhs);
}
}

可以看到有序且不重复
3.TreeSet
特点
- 不可以存储重复元素
- 没有索引
- 可以将元素按照规则进行排序
排序方式一:
默认的排序规则/自然排序
JavaBean类实现Comparable接口,重新里面的抽象方法,再指定比较规则
@Override
public int compareTo(Student o) {
//指定排序的规则
//按照年龄的升序进行排列
return this.getAge() - o.getAge();
}
//1.创建三个学生对象
Student s1 = new Student("zhangsan",23);
Student s2 = new Student("wangwu",25);
Student s3 = new Student("lisi",24);
//2.创建集合对象
TreeSet<Student> ts = new TreeSet<>();
//3.添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
System.out.println(ts);

排序方式二:比较器排序
在集合中重写新的比较器
TreeSet<String> ts = new TreeSet<>((o1, o2) -> {
//按照长度排序
int i = o1.length() - o2.length();
//如果一样长度则按照首字母排序
i = i == 0?o1.compareTo(o2) : i;
return i;
});
//2.添加元素
ts.add("c");
ts.add("ab");
ts.add("df");
ts.add("qwer");
//默认从首字母开始排序
System.out.println(ts);

总结
- 两种比较方式小结
- 自然排序: 自定义类实现Comparable接口,重写compareTo方法,根据返回值进行排序
- 比较器排序: 创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
- 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,必须使用比较器排序
- 两种方式中关于返回值的规则
- 如果返回值为负数,表示当前存入的元素是较小值,存左边
- 如果返回值为0,表示当前存入的元素跟集合中元素重复了,不存
- 如果返回值为正数,表示当前存入的元素是较大值,存右边
63

被折叠的 条评论
为什么被折叠?



