Java初学笔记20
一、泛型
1. 引入
(1)使用传统方法的问题分析,不能对加入到集合ArrayList中的数据类型进行约束(不安全)。同样是Dog类和Cat类,都可以放入集合中,但是遍历时候会出现问题。
(2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对不同的数据类型,先判断后再向下转型会大大增加开销,对效率有影响
2. 介绍
(1)使用泛型可以人为增加约束。编译时,检查添加元素的类型,提高了安全性
(2)遍历时候可以不用向下转型,直接将Object用Dog接收,减少了类型转换的次数,提高效率
(3)通俗理解:可以将泛型理解成一个“变量”,可以在使用时指定为Integer、String、自定义类等等引用类型其中的一个;泛型又有点像是调用方法时传入的一个实参。
(4)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
(5)在类声明或实例化时,只要指定好需要的具体的类型即可。
(6)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
(7)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。
3. 语法
(1)interface接口< T >和class类<K,V>{ },其中,T,K,V不代表值,,而是表示类型。
(2)任意字母都可以。常用T表示,是Type的缩写
(3)泛型的实例化:要在类名后面指定类型参数的值(类型)。
(4)
List< String> strList = new ArrayList< String>();
Iterator< Customer> iterator = customers.iterator():
【泛型示例】
4. 细节
(1)给泛型指向数据类型时,要求是引用类型,不能是基本数据类型
List< Integer> list = new ArrayList< Integer>(); //OK
List< int> list2 = new ArrayList< int>();//错误
(2)在给泛型指定具体类型后,可以传入该类型或者其子类类型
Pig< A> aPig = new Pig< A>(new A());
Pig< A> aPig2 = new Pig< A>(new B()); //正确
class B extends A {
class Pig<E> {
E e;
public Pig(E e) {
this.e = e;
}
public void f() {
System.out.println(e.getClass()); //运行类型
}
(3)泛型的使用形式(推荐简写)
ArrayList<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
//推荐下面写法
ArrayList<Integer> list3 = new ArrayList<>();
List<Integer> list4 = new ArrayList<>();
ArrayList<Pig> pigs = new ArrayList<>()
(4)如果是下面这样写 泛型默认是 Object
ArrayList arrayList = new ArrayList();
二、自定义泛型类
1. 介绍
自己写一个类或者接口,后面定义一些泛型
2. 细节
(1)普通成员可以使用泛型(属性、方法)
(2)使用泛型的数组,不能初始化,因为该数组不确定要开辟多大的空间。
(3)静态方法中不能使用泛型,因为静态方法与对象无关,与类有关
(4)具体使用那一个泛型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
(5)如果在创建对象时,没有指定类型,默认为Object
例子:
class Tiger<T, R, M> {
String name;
R r; //属性使用到泛型
M m;
T t;
//因为数组在 new 不能确定 T 的类型,就无法在内存开空间
T[] ts;
public Tiger(String name) {
this.name = name;
}
public Tiger(R r, M m, T t) {//构造器使用泛型
this.r = r;
this.m = m;
this.t = t;
}
public Tiger(String name, R r, M m, T t) {//构造器使用泛型
this.name = name;
this.r = r;
this.m = m;
this.t = t;
}
//因为静态是和类相关的,在类加载时,对象还没有创建
//所以,如果静态方法和静态属性使用了泛型,JVM 就无法完成初始化
// static R r2;
// public static void m1(M m) {
//
// }
//方法使用泛型
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public R getR() {
return r;
}
public void setR(R r) {//方法使用到泛型
this.r = r;
}
public M getM() {//返回类型可以使用泛型. return m;
}
public void setM(M m) {
this.m = m;
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
@Override
public String toString() {
return "Tiger{" +
"name='" + name + '\'' +
", r=" + r +
", m=" + m +
", t=" + t +
", ts=" + Arrays.toString(ts) +
'}';
}
}
三、自定义泛型接口
1. 语法
interface 接口名<T,Ra>{ }
2. 注意细节
(1)接口中,成员是静态性质的,也不能使用泛型(这个和泛型类规定一样)
(2)泛型接口的类型,新的接口在继承接口时,或者新的类在实现接口时要确定
(3)没有指定类型,默认为Object。
(4)接口中,default默认方法也可以使用泛型
四、自定义泛型方法
1. 语法
修饰符 <T,R…> 返回类型 方法名 (参数列表){ }
泛型方法
public <T,R>void fly(T t,R r) {
}
使用了泛型的方法
public void run(Q q,R r) {
}
2. 注意细节
(1) 泛型方法,可以定义在普通类中,也可以定义在泛型类中
(2)当泛型方法被调用时,类型会确定
(3)public void eat(E e)( ),修饰符后没有<T,R…> eat方法不是泛型方法,而是使用了泛型
五、泛型的继承和通配符
1. 介绍
(1)泛型不具备继承性
List list = new ArrayList( );//不对
List list = new ArrayList<>( );//对
List list = new ArrayList( );//对(默认Object)
2.<?>
支持任意泛型类型
3. <? extends A>
支持A类以及A类的子类,规定了泛型的上限
4.<? super A>
支持A类以及A类的父类,不限于直接父类,规定了泛型的下限
六、JUnit
- 在要测试的方法上添加 @Test
- alt+enter快捷键: Add ‘JUnit5.4’to classpath
七、泛型练习题
package exercise.chapter15;
import java.util.ArrayList;
import java.util.Comparator;
/**
* @Package: exercise.chapter15
* @ClassName: generic02
* @Author: 爱吃凉拌辣芒果
* @CreateTime: 2021/10/24 16:27
* @Description: 泛型练习题
* 定义Employee类
* (1)该类包含:private成员变量name,sal,birthday,其中 birthday为 MyDate类的对象;
* (2)为每一个属性定义getter, setter方法;
* (3)重写toString方法输出name, sal, birthday
* (4)MyDate类包含:private成员变量month,day,year;并为每一个属性定义getter,setter方法;
* (5)创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList 需使用泛型来定义),
* 对集合中的元素进行排序,并遍历输出:
* 排序方式:调用ArrayList的sort方法,传入 Comparator对象[使用泛型],先按照name排序,
* 如果name相同,则按生日日期的先后排序。【即:定制排序】
*/
public class generic02 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("AA",15000,new Mydate(10,24,2021)));
employees.add(new Employee("CC",25000,new Mydate(9,24,2021)));
employees.add(new Employee("AA",15000,new Mydate(11,30,2000)));
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if(!(o1.getName().equals(o2.getName()))){
return o2.getName().compareTo(o1.getName());
}
return o1.getBirthday().compareMydate(o2);
}
});
//遍历
System.out.println(employees);
}
}
class Employee{
private String name;
private double sal;
private Mydate birthday;
public Employee(String name, double sal,Mydate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public Mydate getBirthday() {
return birthday;
}
public void setBirthday(Mydate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "\n员工:" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday;
}
}
class Mydate{
private int month;
private int day;
private int year;
public Mydate(int month, int day, int year) {
this.month = month;
this.day = day;
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "month=" + month +
", day=" + day +
", year=" + year;
}
public int compareMydate(Employee o1){
int n1 = o1.getBirthday().getYear()-this.getYear();
if(n1 != 0){
return n1;
}
int n2 = o1.getBirthday().getMonth()-this.getMonth();
if(n2 != 0) {
return n2;
}
int n3 = o1.getBirthday().getDay()-this.getDay();
if(n3 != 0 ){
return n3;
}
return 0;
}
}
package exercise.chapter15;
import org.junit.jupiter.api.Test;
import java.util.*;
/**
* @Package: exercise.chapter15
* @ClassName: homework01
* @Author: 爱吃凉拌辣芒果
* @CreateTime: 2021/10/24 21:14
* @Description: 泛型练习题
* 定义个泛型类 DAO<T>,在其中定义一个Map成员变量,Map的键为String类型,值为T类型
* 分别创建以下方法:
* (1) public void save(String id,T entity):保存T类型的对象到Map成员变量中
* (2) public T get(String id): 从 map中获取id对应的对象
* (3) public void update(String id,T entity):替换map中key为id的内容,改为entity对象
* (4) public List<T> list():返回map中存放的所有T对象
* (5) public void delete(String id):删除指定id对象
* 定义一个 User类:
* 该类包含:private成员变量(int类型)id, age;(String类型) name.
* 创建DAO类的对象,分别调用其 save、get、update、list、delete方法来操作User对象,
* 使用Junit 单元测试类进行测试。
*/
public class homework01 {
public static void main(String[] args) {
}
@Test
public void Test(){
DAO<User> integerDAO = new DAO<>();
integerDAO.save("1号",new User(1,20,"爱吃凉拌辣芒果"));
integerDAO.save("2号",new User(2,20,"小梅"));
integerDAO.save("3号",new User(3,20,"大志"));
System.out.println(integerDAO.get("2号"));
integerDAO.update("1号",new User(4,10,"小可爱"));
List<User> list = integerDAO.list();
System.out.println(list);
integerDAO.delete("3号");
}
}
class DAO<T>{
private Map<String, T> map = new HashMap<>();
public void save(String id,T entity){
map.put(id,entity);
}
public T get(String id){
return map.get(id);
}
public void update(String id,T entity){
map.replace(id,entity);
}
public List<T> list(){
List<T> list = new ArrayList<>();
Set<String> strings = map.keySet();
for (String str : strings) {
T t = map.get(str);
list.add(t);
}
return list;
}
public void delete(String id){
map.remove(id);
}
}
class User{
private int id;
private int age;
private String name;
public User(int id, int age, String name) {
this.id = id;
this.age = age;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "\nUser{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}