今日内容:
- Set集合
- 泛型
- 可变参数
总结:
Set集合的特点
Set集合的基本使用
new HashSet<>();
总结:
哈希值简介
* 用于计算存储元素的位置的. 提高存储元素和取出元素的效率的
如何获取哈希值
* hashCode()
哈希值的特点
总结:
HashSet集合的特点
数据结构:
JDK8之前: 哈希表(数组 + 链表)
JDK8之后: 哈希表(数组 + 链表 + 红黑树)
HashSet<String> set = new HashSet<>();
set.add("abc");
set.add("def");
set.add("egi");
for (String s : set) {
System.out.println(s);
}
理解即可
LinkedHashSet集合特点
数据结构:
数组+链表 + 链表 ==> 数组 + 双向链表
LinkedHashSet 集合基本使用
public class LinkedHashSetDemo01 {
public static void main(String[] args) {
LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add(new String("重地"));
linkedHashSet.add(new String("通话"));
linkedHashSet.add(new String("cde"));
System.out.println(linkedHashSet);
}
}
总结:
数据结构:
二叉树 --> 红黑树
存储学生对象并遍历,创建TreeSet集合使用无参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
用TreeSet集合存储自定义对象,无参构造方法使用的是自然排序对元素进行排序的
自然排序,就是让元素所属的类实现Comparable接口,重写compareTo(T o)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
*案例代码:*
public class TreeSetDemo02 {
public static void main(String[] args) {
//创建集合对象
TreeSet<Student> ts = new TreeSet<Student>();
//创建学生对象
Student s1 = new Student("xishi", 29);
Student s2 = new Student("wangzhaojun", 28);
Student s3 = new Student("diaochan", 30);
Student s4 = new Student("yangyuhuan", 33);
Student s5 = new Student("linqingxia",33);
Student s6 = new Student("linqingxia",33);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
public class Student implements Comparable<Student> {
private String name;
private int age;
@Override
public int compareTo(Student s) {
// return 0; 表示比较的两个对象相等
// return 1; 表示的是按照升序排序
// return -1; 表示的是按照降序排序
//按照年龄从小到大排序
// int num = this.age - s.age;
// 按照年龄从大到小排序
int num = s.age - this.age; // 主要条件
// s.name.length() - this.name.length();
// s.name.charAt(0) - this.name.charAt(0);
//年龄相同时,按照姓名的字母顺序排序
// 次要条件
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
存储学生对象并遍历,创建TreeSet集合使用带参构造方法
要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序
用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
案例代码:
public class TreeSetDemo {
public static void main(String[] args) {
//创建集合对象
// 先定义一个Comparator实现类 重写compare方法,在创建TreeSet的时候,将omparator实现类的对象给这个构造
TreeSet<Student> ts = new TreeSet<Student>(new ComparatorImpl());
//创建学生对象
Student s1 = new Student("xishi", 29);
Student s2 = new Student("wangzhaojun", 28);
Student s3 = new Student("diaochan", 30);
Student s4 = new Student("yangyuhuan", 33);
Student s5 = new Student("linqingxia",33);
Student s6 = new Student("linqingxia",33);
//把学生添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getAge());
}
}
}
class ComparatorImpl implements Comparator<Student>{
public int compare(Student s1, Student s2) {
//this.age - s.age
//s1,s2 s1 - s2 按照升序进行排序 s2 - s1 : 按照降序进行排序
int num = s1.getAge() - s2.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName()) : num;
return num2;
}
}
public class Student {
private String name;
private int age;
}
public class TreeSetDemo {
public static void main(String[] args) {
//创建TreeSet集合对象,通过比较器排序进行排序
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// int num = (s2.getChinese()+s2.getMath())-(s1.getChinese()+s1.getMath());
//主要条件 按照总成绩的降序排序
int num = s2.getSum() - s1.getSum();
//次要条件 如果总成绩相等 就按照语文成绩进行排序 按照语文的升序进行排序
int num2 = num == 0 ? s1.getChinese() - s2.getChinese() : num;
// 如果是总成绩一样 语文成绩也一样就按照名字进行排序 ,按照自然顺序进行排序
int num3 = num2 == 0 ? s1.getName().compareTo(s2.getName()) : num2;
return num3;
}
});
//创建学生对象
Student s1 = new Student("林青霞", 98, 100);
Student s2 = new Student("张曼玉", 95, 95);
Student s3 = new Student("王祖贤", 100, 93);
Student s4 = new Student("柳岩", 100, 97);
Student s5 = new Student("风清扬", 98, 98);
Student s6 = new Student("左冷禅", 97, 99);
// Student s7 = new Student("左冷禅", 97, 99);
Student s7 = new Student("赵云", 97, 99);
//把学生对象添加到集合
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
//遍历集合
for (Student s : ts) {
System.out.println(s.getName() + "," + s.getChinese() + "," + s.getMath() + "," + s.getSum());
}
}
}
public class Student {
private String name;
private int chinese;
private int math;
public Student() {
}
public Student(String name, int chinese, int math) {
this.name = name;
this.chinese = chinese;
this.math = math;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getChinese() {
return chinese;
}
public void setChinese(int chinese) {
this.chinese = chinese;
}
public int getMath() {
return math;
}
public void setMath(int math) {
this.math = math;
}
public int getSum() {
return this.chinese + this.math;
}
}
编写一个程序,获取10个1*20之间的随机数,要求随机数不能重复,并在控制台输出
*案例代码: *
Set<Integer> set = new TreeSet<Integer>();
//创建随机数对象
Random r = new Random();
//判断集合的长度是不是小于10
while (set.size()<7) {
//产生一个随机数,添加到集合
// int number = r.nextInt(20) + 1;
set.add(r.nextInt(35) + 1);
}
//遍历集合
for(Integer i : set) {
System.out.println(i);
}
总结:
泛型概述
广泛的类型 只有在使用的时候才能确定是一个什么样的类型
泛型定义格式
<类型>
<类型1,类型2>
泛型的好处
将运行时期的异常提前到了编译时期
避免了强制类型转换(避免出现 ClassCastException)
有泛型没有写,泛型的类型默认都是Object
泛型在编译时期是有泛型 运行时期是没有泛型的 泛型擦除
如果一个类后面有<>
第一: 可以不写泛型 泛型的类型默认都是Object
第二: 写泛型
如果一个类后面没有<>,绝对不允许写泛型
总结:
public class 类名<类型>{
}
T : Type
E : Element
K : Key
V : Value
public class StudentDemo01 {
public static void main(String[] args) {
Student<PC> objectStudent = new Student<>();
objectStudent.setType(new PC());
}
}
public class Student<T> {
private T type;
public T getType() {
return type;
}
public void setType(T type) {
this.type = type;
}
}
总结:
// 定义泛型方法
public <T> void 方法名(T t){
}
总结:
public interface 接口名<类型>{
}
实现泛型接口的格式:
public class InterImpl<T> implements Inter<T> {
@Override
public void method(T t) {
}
}
public class InterImplA implements Inter<String> {
@Override
public void method(String s) {
}
}
总结:
类型通配符的分类
类型通配符:>
public static void printArrayList(ArrayList> list) {}
类型通配符上限: extends 类型>
List extends Number>:它表示的类型是Number或者其子类型
类型通配符下限: super 类型>
List super Number>:它表示的类型是Number或者其父类型
总结:
什么是可变参数
参数的个数是可变的, 数据类型已经确定了,但是个数不能确定,这个时候就可以使用可变参数
可变参数定义格式
格式:
数据类型…变量名
可变参数的注意事项
总结:
// 将数组转换成List集合
* public static <T> List<T> asList(T... a):返回由指定数组支持的固定大小的列表
// 将集合转换成数组
Object[] toArray()
<T> T[] toArray(T[] a)
List接口中有一个静态方法:
Set接口中有一个静态方法:
LinkedHashSet基本使用
使用LinkedHashSet存储以下元素:
“王昭君”,“王昭君”,“西施”,“杨玉环”,“貂蝉”。
使用迭代器和增强for循环遍历LinkedHashSet。
public class Demo_1 {
public static void main(String[] args) {
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.add("王昭君");
lhs.add("王昭君");
lhs.add("西施");
lhs.add("杨玉环");
lhs.add("貂蝉");
Iterator<String> iterator = lhs.iterator();
while (iterator.hasNext()) {
String s = iterator.next();
System.out.println(s);
}
System.out.println("~~~~~~~~~~~~");
for (String lh : lhs) {
System.out.println(lh);
}
}
}
根据需求完成代码
1.定义一个Person类
成员变量:name age
构造方法、get和set、toString
2.创建三个Person对象
Person(“张三”,23);
Person(“李四”,24);
Person(“张三”,23);
3.将这三个对象存储到Set集合中。(同姓名同年龄的为重复值、不存储)
4.使用迭代器遍历集合
实现了Comparable接口的Person类
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;
}
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 String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Person person) {
int nameDiff = this.name.compareTo(person.name);
return nameDiff == 0 ? this.age - person.age : nameDiff;
}
}
测试类
public class PersonDemo {
public static void main(String[] args) {
Person p1 = new Person("张三", 23);
Person p2 = new Person("李四", 24);
Person p3 = new Person("张三", 23);
Set<Person> set = new TreeSet<>();
set.add(p1);
set.add(p2);
set.add(p3);
Iterator<Person> it = set.iterator();
while (it.hasNext()) {
Person p = it.next();
System.out.println(p);
}
}
}
根据需求完成代码
1.键盘录入一个字符串,去掉其中重复字符
2.打印出不同的那些字符,必须保证顺序。
例如输入:aaaabbbcccddd,打印结果为:abcd。
public class SetDemo_03 {
public static void main(String[] args) {
Set<Character> set = new TreeSet<>(); //字符的封装类
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串:");
String str = sc.next();
char[] arr = str.toCharArray(); //将字符串转换为字符数组
for (char c : arr) {
set.add(c);
}
System.out.println(set);
}
}
已知数组存放一批QQ号码,QQ号码最长为11位,最短为5位
String[] str{“12345”,“67891”,“12347809933”,“98765432102”,“67891”,“12347809933”};
将该数组里面的所有qq号都存放在LinkedList中,将list中重复元素删除,
将list中所有元素分别用迭代器和增强for循环打印出来。
public class Demo_05 {
dddd
public static void main(String[] args) {
String[] str = {"12345","67891",
"12347809933","98765432102","67891","12347809933"};
Set<String> set = new HashSet<>();
Collections.addAll(set, str);
LinkedList<String> list = new LinkedList<>(set);
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("~~~~~~~~");
for (String s : list) {
System.out.println(s);
}
}
}
``
#### 练习四
* 需求:
> 已知数组存放一批QQ号码,QQ号码最长为11位,最短为5位<br>
String[] str{"12345","67891","12347809933","98765432102","67891","12347809933"};<br>
将该数组里面的所有qq号都存放在LinkedList中,将list中重复元素删除,
将list中所有元素分别用迭代器和增强for循环打印出来。
```java
public class Demo_05 {
dddd
public static void main(String[] args) {
String[] str = {"12345","67891",
"12347809933","98765432102","67891","12347809933"};
Set<String> set = new HashSet<>();
Collections.addAll(set, str);
LinkedList<String> list = new LinkedList<>(set);
Iterator<String> it = list.iterator();
while (it.hasNext()) {
String s = it.next();
System.out.println(s);
}
System.out.println("~~~~~~~~");
for (String s : list) {
System.out.println(s);
}
}
}