Day17
泛型
泛型概述
泛型:是JDK5中引入的特性,它提供了编译时类型安全监测机制
泛型的好处:
- 把运行时期的问题提前到了编译期
- 避免了强制类型转换
泛型可以使用的地方:
- 类后面,这样的类称为泛型类
- 方法申明上,这样的方法称为泛型方法
- 接口后面,这样的接口称为泛型接口
总结:
如果一个类的后面有,表示这个类是一个泛型类;创建泛型类的对象时,必须要给这个泛型确定具体的数据类型。
泛型定义格式
- <类型>:指定一种类型的格式。尖括号里可以任意书写,按照变量的定义规则即可。一般只写一个字母,比如
- <类型1,类型2,…>:指定多种类型的格式,多种类型之间用逗号隔开。比如:<E,T> <Q,M>
定义一个泛型类FirstE.java
泛型类
定义格式:
- 格式:修饰符 class 类名<类型>{}
- 范例:public class Generic{}
public class FirstE<E> {
private E element;
public E getElement() {
return element;
}
public void setElement(E element) {
this.element = element;
}
}
测试类
public class ETest {
public static void main(String[] args) {
FirstE<String> f1 = new FirstE<>();
f1.setElement("自定义泛型");
FirstE<Integer> f2 = new FirstE<>();
f2.setElement(2233);
System.out.println(f1.getElement()); //自定义泛型
System.out.println(f2.getElement()); //2233
}
}
泛型方法
定义格式:
- 格式:修饰符<类型> 返回值类型 方法名(类型 变量名){}
- 范例:public void show(T t){}
import java.util.ArrayList;
/*
定义一个泛型方法,传递一个集合和四个元素,将元素添加到集合并返回
*/
public class EMethod {
public static void main(String[] args) {
ArrayList<String> list1 = addElement(new ArrayList<>(),"a","b","c","d");
System.out.println(list1); //[a, b, c, d]
ArrayList<Integer> list2 = addElement(new ArrayList<>(), 1, 2, 3, 4);
System.out.println(list2); //[1, 2, 3, 4]
}
public static <T> ArrayList<T> addElement(ArrayList<T> list,T t1,T t2,T t3,T t4){
list.add(t1);
list.add(t2);
list.add(t3);
list.add(t4);
return list;
}
}
泛型接口
泛型接口的使用方式:
- 实现类也不给泛型
- 实现类确定具体的数据类型
泛型接口的定义格式:
- 格式:修饰符 interface 接口名<类型>
- 范例:public interface Generic{}
public class GenericityInterface {
public static void main(String[] args) {
GenericityImpl1<String> genericity = new GenericityImpl1<>();
genericity.method("泛型接口...");
GenericityImpl2 genericity2 = new GenericityImpl2();
genericity2.method(2233);
}
}
interface Genericity<E>{
public abstract void method(E e);
}
class GenericityImpl1<E> implements Genericity<E>{
@Override
public void method(E e) {
System.out.println(e); //泛型接口...
}
}
class GenericityImpl2 implements Genericity<Integer>{
@Override
public void method(Integer integer) {
System.out.println(integer); //2233
}
}
类型通配符
- 类型通配符:<?>
- ArrayList<?>:表示元素类型未知的ArrayList,它的元素可以匹配任何的类型
- 但是并不能把元素添加得到ArrayList中了,获取出来的也是父类类型
- 类型通配符上限:<?extends 类型>
- 比如:ArrayList<?extends Number>:它表示Number类和所有子类
- 类型通配符下限:<?super 类型>
import java.util.ArrayList;
public class Tongpei {
public static void main(String[] args) {
ArrayList<String> list1 = new ArrayList<>();
ArrayList<Integer> list2 = new ArrayList<>();
ArrayList<Number> list3 = new ArrayList<>();
ArrayList<Object> list4 = new ArrayList<>();
//printList(list1);
//printList(list2);
method1(list2);
method1(list3);
//method1(list4);不是Number的子类型不能传入
method2(list4);
}
//表示传递进来的可以是Number类型,也可以是Number所有的子类型
private static void method1(ArrayList<? extends Number> list) { }
//表示传递进来的可以是Number类型,也可以是Number所有的父类型
private static void method2(ArrayList<? super Number> list) { }
private static void printList(ArrayList<?> list) { }
}
Set
set集合特点
- 可以去除重复
- 存取顺序不一致
- 没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取、删除Set集合里面的元素
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class SetTest1 {
public static void main(String[] args) {
Set<String> set = new TreeSet<>();
set.add("ccc");
set.add("aaa");
set.add("aaa");
set.add("bbb");
Iterator<String> it = set.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println("--------------");
for (String s : set) {
System.out.println(s);
}
}
}
运行结果:
TreeSet集合特点
- 不包含重复元素的集合
- 没有带索引的方法
- 可以将元素按照规则进行排序
自然排序原理
- 若返回值为负数,表示当前存入的元素是较小值,存左边
- 若返回值为0,表示当前存入的元素跟集合中元素重复了,不存
- 若返回值为正数,表示当前存入的元素是较大值,存右边
示例:
public class Student implements Comparable<Student> {
private String name;
private int 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;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public Student() {
}
@Override
public int compareTo(Student o) {
//按照年龄进行排序
//this表示当前待存入的age,o表示集合中已存入的age,若有多个则依次进行比较
int i = this.age - o.age;
return i;
}
}
测试类:
import java.util.TreeSet;
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>();
Student st1 = new Student("玲",13);
Student st2 = new Student("七宝",7);
Student st3 = new Student("戈薇",18);
ts.add(st1);
ts.add(st2);
ts.add(st3);
System.out.println(ts);
}
}
运行结果:
案例:按照年龄排序
按照年龄从小到大排序,如果年龄一样,则按照姓名首字母排序,如果姓名和年龄一样,才认为是同一个学生对象,不存入;
public class Student implements Comparable<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;
}
@Override
public int compareTo(Student o) {
int result = this.age - o.age;
//三目运算,若年龄一样按姓名排
result = result == 0 ? this.name.compareTo(o.name) : result;
return result;
}
}
import java.util.TreeSet;
public class StudentTest {
public static void main(String[] args) {
TreeSet<Student> ts = new TreeSet<>();
Student st1 = new Student("岚岚",18);
Student st2 = new Student("图图",11);
Student st3 = new Student("泡泡",11);
Student st4 = new Student("飞飞",16);
Student st5 = new Student("飞飞",16);
ts.add(st1);
ts.add(st2);
ts.add(st3);
ts.add(st4);
ts.add(st5);
System.out.println(ts);
}
}
运行结果:
比较器排序Comparator的使用
- TreeSet的带构造方法使用的是比较器排序对元素进行排序的
- 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写compare(T o1,T o2)方法
- 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写
练习:
自定义Teacher老师类,属性为姓名和年龄,请按照年龄排序,如果年龄一样,则按照姓名进行排序,姓名都是用英文字母表示;
public class Teacher {
private String name;
private int age;
public Teacher(String name, int age) {
this.name = name;
this.age = age;
}
public Teacher() {
}
@Override
public String toString() {
return "Teacher{" +
"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;
}
}
import java.util.Comparator;
import java.util.TreeSet;
public class TeacherTest {
public static void main(String[] args) {
//匿名内部类
TreeSet<Teacher> ts = new TreeSet<>(new Comparator<Teacher>() {
@Override
public int compare(Teacher o1, Teacher o2) {
int result = o1.getAge() - o2.getAge();
result = result == 0 ? o1.getName().compareTo(o2.getName()) : result;
return result;
}
});
Teacher t1 = new Teacher("make",24);
Teacher t2 = new Teacher("rose",23);
Teacher t3 = new Teacher("jack",24);
Teacher t4 = new Teacher("tom",21);
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t4);
System.out.println(ts);
}
}
运行结果:
补充:中文字符串排序
两种比较方式小结
- 自然排序:自定义实现类接口Comparable接口,重写compareTo方法,根据返回值进行排序
- 比较器排序:创建TreeSet对象的时候传递Comparator的实现类对象,重写compare方法,根据返回值进行排序
- 在使用的时候,默认使用自然排序,当自然排序不满足现在的需求时,使用比较器排序
案例:按照字符串长短排序
自行选择比较器排序和自然排序两种方式;存入四个字符串,“c”,“ab”,“df”,“qwem”,按照长度排序,如果一样长则按照首字母排序;
import java.util.Comparator;
import java.util.TreeSet;
public class AnliTest {
public static void main(String[] args) {
//由于String的原码已经重写过了Comparable接口里的方法,所以,只能用比较器排序
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
int result = o1.length() - o2.length();
result = result == 0 ? o1.compareTo(o2) : result;
return result;
}
});
ts.add("c");
ts.add("ab");
ts.add("df");
ts.add("qwem");
System.out.println(ts);
}
}
运行结果:
练习1
已知数组信息如下:{2.2,5.5,6.6,2.2,8.8,1.1,2.2,8.8,5.5,2.2,6.6},请使用代码找出上面数组中的所有的数据,要求重复的数据只能保留一份;
import java.util.HashSet;
public class Lian1 {
public static void main(String[] args) {
double[] arr = {2.2,5.5,6.6,2.2,8.8,1.1,2.2,8.8,5.5,2.2,6.6};
//将数组中的元素存入set集合,会自动去除重复的部分
HashSet<Double> hs = new HashSet<>();
for (double v : arr) {
hs.add(v);
}
System.out.println(hs);
}
}
运行结果:
练习2
随机生成8个不重复的10至20之间的随机数并保存Set集合中,然后打印出集合中所有的数据;使用TreeSet集合实现;
import java.util.Random;
import java.util.TreeSet;
public class Lian2 {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
Random r = new Random();
//set集合中不会存储重复的数
//ts中有8个数的时候不满足<8,结束循环
while (ts.size()<8){
ts.add(r.nextInt(11)+10);
}
System.out.println(ts);
}
}
运行结果:
练习3
键盘输入3本书按照价格从低到高排序后输出,如果价格相同则按照书名的自然顺序排序;
要求
- 书以对象形式存在,包含书名和价格(int类型)两个属性;
- 要求即使直接打印书对象的时候,也能看到书的名称和价格,而不是书对象的地址值;
- 分别使用自然排序和比较器排序实现效果;
自然排序方式(在JavaBean类中实现Comparable)
public class Book implements Comparable<Book>{
private String name;
private int price;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public Book() {
}
@Override
public int compareTo(Book o) {
//主要条件
int result = this.price - o.price;
//次要条件
return result == 0 ? this.name.compareTo(o.name) : result;
}
}
测试类:
import java.util.Scanner;
import java.util.TreeSet;
public class BookTest {
public static void main(String[] args) {
TreeSet<Book> ts = new TreeSet<>();
Scanner sc = new Scanner(System.in);
int i = 1;
while (true){
System.out.println("请输入第"+i+"本书的书名:");
String name = sc.next();
System.out.println("请输入第"+i+"本书的价格(整数):");
int price = sc.nextInt();
Book b = new Book(name,price);
ts.add(b);
i++;
System.out.println("输入1继续添加,其他数字则结束添加");
int ch = sc.nextInt();
if(ch!=1){
break;
}
}
System.out.println("你一共添加了"+ts.size()+"本书,分别是");
for (Book book : ts) {
System.out.println(book);
}
}
}
比较器方式(不用实现接口)
public class Book{
private String name;
private int price;
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
public Book(String name, int price) {
this.name = name;
this.price = price;
}
public Book() {
}
}
测试类:
import java.util.Scanner;
import java.util.TreeSet;
public class BookTest {
public static void main(String[] args) {
TreeSet<Book> ts = new TreeSet<Book>((b1,b2)->{
//主要条件
int result = b1.getPrice()-b2.getPrice();
//次要条件
return result == 0 ? b1.getName().compareTo(b2.getName()) : result;
});
Scanner sc = new Scanner(System.in);
int i = 1;
while (true){
System.out.println("请输入第"+i+"本书的书名:");
String name = sc.next();
System.out.println("请输入第"+i+"本书的价格(整数):");
int price = sc.nextInt();
Book b = new Book(name,price);
ts.add(b);
i++;
System.out.println("输入1继续添加,其他数字则结束添加");
int ch = sc.nextInt();
if(ch!=1){
break;
}
}
System.out.println("你一共添加了"+ts.size()+"本书,分别是");
for (Book book : ts) {
System.out.println(book);
}
}
}
运行结果: