第十三章、 泛型
13.1 泛型语法
13.1.1 泛型的引入与入门
- 看一个需求
(1). 请编写程序,在ArrayList中,添加3个Dog对象
(2). Dog对象含有name和age,并输出name和age(要求使用getXxx())
使用传统的方法来解决 -->引出泛型
package chapter13.generic_;
import java.util.ArrayList;
/**
* @aim java基础学习
* @note java笔记
*/
@SuppressWarnings({"all"})
public class Generic01 {
public static void main(String[] args) {
//传统方法
ArrayList arrayList = new ArrayList();
arrayList.add(new Dog("小呆呆", 2));
arrayList.add(new Dog("超人强", 3));
arrayList.add(new Dog("波比", 4));
//假如程序员不小心把其他类型的数据放入这个arrayList集合中,明显会发生ClassCastException异常,
//这是一个运行时异常,编译器发现不了。
// arrayList.add(123);
//使用增强for输出
for (Object o :arrayList) {
//默认是Object,需要进行向下转型为Dog
Dog dog =(Dog) o;
System.out.println(dog.getName()+"-"+dog.getAge());
}
/*
小呆呆-2
超人强-3
波比-4
*/
}
}
class Dog{
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
-
使用传统方法的问题分析上面代码出现的问题
(1). 不能对加入到集合ArrayList中的数据类型进行约束(不安全)
(2). 遍历的时候,需要进行类型转换,如果集合中的数据量比较大时,对效率是有影响的。 -
泛型快速体验-用泛型来解决前面的问题。
package chapter13.improve_;
import java.util.ArrayList;
/**
* @aim java基础学习
* @note java笔记
*/
public class Generic02 {
public static void main(String[] args) {
//使用泛型进行修改
// ArrayList<Dog>表示存放到 ArrayList集合中的元素类型是Dog类型
// public class ArrayList<E> {} 其中E就是泛型,也就是形参,而Dog就是实参
ArrayList<Dog> dogs = new ArrayList<>();
dogs.add(new Dog("小呆呆", 2));
dogs.add(new Dog("超人强", 3));
dogs.add(new Dog("波比", 4));
//当不小心把其他类型加入到ArrayList,就会发生编译异常
// dogs.add(123);
//在使用增强for的时候,也可以直接使用Dog类型,而不是Object,就省略向下转型
for (Dog dog :dogs) {
System.out.println(dog.getName()+"-"+dog.getAge());
}
/*
小呆呆-2
超人强-3
波比-4
*/
}
}
class Dog{
private String name;
private int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
- 泛型的好处
(1). 编译时,检查添加元素的类型,提高了安全性
(2). 减少了类型转换的次数,提供效率
(3). 若不使用泛型,在添加数据到ArrayList时,会先转成Object,在取出时,还需转成其他类型。如上面的Dog。若使用泛型,在添加数据和取出数据,都不需要类型转换,提高效率。
(4). 不在提示编译警告
13.1.2 泛型说明
- 泛型介绍
(1). 泛型又称参数化类型,是jkd5.0出现的新特性,解决数据类型的安全性问题
(2). 在类声明或实例化时只要指定好需要的具体的类型即可,即通过方法或构造器进行指定。
(3). Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮。
(4). 泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值类型,或者是参数类型。
package chapter13.generic_;
/**
* @aim java基础学习
* @note java笔记
*/
public class Generic03 {
public static void main(String[] args) {
Person<String> person = new Person<String>("hello");
// Person<String> person = new Person<String>(1223);//报错
/*
可以这样理解:
class Person<String>{
String s;//E 表示 s的数据类型,具体是什么类型,在定义Person对象的时候就可以指定,即在编译期间,就可以确定E是什么类型
public Person(String s) {//E也可以是参数类型
this.s = s;
}
public String f(){//返回类型也可以使用E
return s;
}
}
*/
Person<Integer> person2 = new Person<Integer>(123);
/*
class Person<Integer>{
Integer s;//E 表示 s的数据类型,具体是什么类型,在定义Person对象的时候就可以指定,即在编译期间,就可以确定E是什么类型
public Person(Integer s) {//E也可以是参数类型
this.s = s;
}
public Integer f(){//返回类型也可以使用E
return s;
}
}
*/
}
}
class Person<E>{
E s;//E 表示 s的数据类型,具体是什么类型,在定义Person对象的时候就可以指定,即在编译期间,就可以确定E是什么类型
public Person(E s) {//E也可以是参数类型
this.s = s;
}
public E f(){//返回类型也可以使用E
return s;
}
}
13.1.3 泛型的语法
-
泛型的声明
interface 接口{}和class 类<K,V>{}
//比如:List、ArrayList
(1). 说明其中T、K、V不代表值,而是表示类型
(2). 任意字母都可以。常用T表示,是Type的缩写 -
泛型的实例化:
要在类名后面指定类型参数的值(类型)。如:
(1). List strList = new ArrayList();
(2). Iterator iterator = customer.iterator(); -
泛型使用举例 GenericExercise.java
(1). 创建3个学生对象
(2). 分别放入到HashSet和HashMap中,要求Key是String name,Value就是学生对象
(3). 使用两种方式遍历
package chapter13.generic_;
import java.util.*;
/**
* @aim java基础学习
* @note java笔记
*/
public class GenericExercise01 {
public static void main(String[] args) {
HashSet<Student> students = new HashSet<>();//public class HashSet<E>{}
students.add(new Student("小明", 18));
students.add(new Student("小红", 15));
students.add(new Student("小花", 17));
for (Student student : students) {
//使用泛型后,取出来的对象就Student
System.out.println(student);
}
HashMap<String, Student> hashMap = new HashMap<>();//public class HashMap<K,V>{}
hashMap.put("第一个学生", new Student("小明", 18));
hashMap.put("第二个学生", new Student("小红", 15));
hashMap.put("第三个学生", new Student("小花", 17));
/*
(1).为什么hashMap.entrySet().var直接回车就会自动填充Set<Map.Entry<String, Student>>这里面的泛型
(2).原本是Object的
(3).因为entrySet()是HashMap<K,V>类的方法,在实例化的时候这里的k和V就会传入具体的类型,就会替换为具体的类型
(4).那么Set<Map.Entry<K,V>> entrySet()这个方法里面K和V自然也会替换为具体的类型
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
*/
Set<Map.Entry<String, Student>> set = hashMap.entrySet();
/*
(1).为什么set.iterator().var也会自动填充Iterator<Map.Entry<String, Student>> 里面的类型,同上面的原理
final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
public final int size() { return size; }
public final void clear() { HashMap.this.clear(); }
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
}
*/
Iterator<Map.Entry<String, Student>> iterator = set.iterator();
while (iterator.hasNext()) {//使用itit模版,也会自动填充为相应的类型,而不是Object啦
Map.Entry<String, Student> next = iterator.next();
System.out.println(next.getKey()+":"+next.getValue());
}
}
}
/*
Student{name='小红', age=15}
Student{name='小明', age=18}
Student{name='小花', age=17}
第一个学生:Student{name='小明', age=18}
第三个学生:Student{name='小花', age=17}
第二个学生:Student{name='小红', age=15}
*/
class Student {
public String name;
public int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 泛型使用的注意事项和细节 GenericDetail.java
(1). interface List{} 和public class HashSet{}………等等
说明:T、E只能是引用类型
看看下面语句是否正确?
List list = new ArrayList();//ok
List list2 = new ArrayList();//报错
(2). 在给泛型指定具体类型后,可以传入该类型或者子类类型
(3). 泛型使用形式
List list1 = new ArrayList();
List list2 = new ArrayList<>();
如果这样写List List3 = new ArrayList();默认给它的泛型是,而E就是Object
package chapter13.generic_;
import chapter8.interface_.E;
import java.util.ArrayList;
import java.util.List;
/**
* @aim java基础学习
* @note java笔记
*/
public class GenericDetail {
public static void main(String[] args) {
//1. 给泛型指向数据类型时,要求是引用类型,不能是基本数据类型
List<Integer> list = new ArrayList<Integer>();//ok
// List<int> list2 = new ArrayList<int>();//报错
//(2). 实例化C指定泛型为A引用类型,这里可以传A类型或者A的子类B
C<A> ac = new C<A>(new A());
ac.f();//class chapter13.generic_.A
C<A> ab = new C<A>(new B());
ab.f();//class chapter13.generic_.B
//(3). 泛型使用形式,第二种写法是简写(推荐):编译器会自动进行类型推断
List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<>();
List List3 = new ArrayList();//默认给它的泛型是<E>,而E就是Object
}
}
class A{}
class B extends A{}
class C<E>{
E e;
public C(E e) {
this.e = e;
}
public void f(){
System.out.println(e.getClass());
}
}
- 泛型练习
定义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需使用泛型来定义),对集合中的元素进行排序,并遍历输出:
(6). 排序方式:调用ArrayList的sort方法,传入Comparator对象【使用泛型】,先按照name【a-z】排序,如果name相同,则按生日日期的先后排序【1-9】【即:定制排序】
- Employee类
package chapter13.generic_;
/**
* @aim java基础学习
* @note java笔记
*/
@SuppressWarnings({"all"})
public 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 "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
- MyDate类
package chapter13.generic_;
/**
* @aim java基础学习
* @note java笔记
*/
@SuppressWarnings({"all"})
public class MyDate implements Comparable<MyDate>{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public int getMonth() {
return month;
}
public int getDay() {
return day;
}
@Override
public String toString() {
return "MyDate{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
//为什么这里打出compareTo一回车MyDate就自动填充了,因为 Comparable<MyDate>泛型已经指定了MyDate类型,
// 那么重写的时候直接打出compareTo自动填充
@Override
public int compareTo(MyDate o) {
//如果name相同,就先比较year
int yearMinus = year-o.getYear();
if(yearMinus!=0){return yearMinus;}
//如果year相同,再比较month
int monthMinus = month-o.getMonth();
if(monthMinus!=0){return monthMinus;}
//如果month相同,最后比较day
return day-o.getDay();
}
}
- 执行程序类GenericExercise02
package chapter13.generic_;
import java.util.ArrayList;
import java.util.Comparator;
/**
* @aim java基础学习
* @note java笔记
*/
@SuppressWarnings({"all"})
public class GenericExercise02 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<Employee>();
employees.add(new Employee("Rose",10000,new MyDate(2003,8,9)));
employees.add(new Employee("Rose",10000,new MyDate(2002,5,23)));
employees.add(new Employee("Mak",70000,new MyDate(2001,10,4)));
employees.add(new Employee("Jerry",40000,new MyDate(2002,2,28)));
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee emp1, Employee emp2) {
//先对传入的参数进行验证
if(!(emp1 instanceof Employee) && emp2 instanceof Employee){
System.out.println("类型不匹配");
return 0;
}
//比较name
int compare=emp1.getName().compareTo(emp2.getName());
if(compare!=0){
return compare;
}
//比较年月日
return emp1.getBirthday().compareTo(emp2.getBirthday());
}
});
for (Employee employee :employees) {
System.out.println(employee);
}
//Employee{name='Jerry', sal=40000.0, birthday=MyDate{year=2002, month=2, day=28}}
//Employee{name='Mak', sal=70000.0, birthday=MyDate{year=2001, month=10, day=4}}
//Employee{name='Rose', sal=10000.0, birthday=MyDate{year=2002, month=5, day=23}}
//Employee{name='Rose', sal=10000.0, birthday=MyDate{year=2003, month=8, day=9}}
}
}
13.2 自定义泛型
13.2.1 自定义泛型类
- 基本语法
class 类名<T,R..>{
成员
}
- 注意细节
(1). 普通成员可以使用泛型(方法、属性)
(2). 使用泛型的数组,不能初始化
(3). 静态方法中不能使用类的泛型
(4). 泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
(5). 如果在创建对象时,没有指定类型,默认为Object
package chapter13.customgeneric;
/**
* @aim java基础学习
* @note java笔记
*/
public class CustomGeneric_ {
public static void main(String[] args) {
}
}
//1.Tiger 后面加有泛型,所以就可以称 为自定义泛型类
//2.T,R,M 是泛型的标识符, 一般是单个大写字母
//3.泛型标识符可以有多个。
//4.普通成员可以使用泛型(方法、属性)
//5.使用泛型的数组,不能初始化
//6.静态方法中不能使用类的泛型
//7.泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型)
//8.如果在创建对象时,没有指定类型,默认为Object
class Tiger<T,R,M>{
String name;
R r;//属性使用泛型
M m;
T t;
//报错,泛型的数组不能初始化。因为数组在new时不能确定T的类型,就无法在内存开辟空间,在指定类型后才可new
// T[] ts = new T[8];
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 m(){}//报错
public String getName() {
return name;
}
public R getR() {//方法使用泛型
return r;
}
public M getM() {
return m;
}
public T getT() {
return t;
}
}
- 自定义泛型类练习
思考下面自定义泛型代码是否正确,并说明原因。
CustomGenericExercise.java
package chapter13.customgeneric;
/**
* @aim java基础学习
* @note java笔记
*/
public class CustomGenericExercise {
public static void main(String[] args) {
Person<Double, String, Integer> jack = new Person<>("jack");//ok
//通过方法去指定泛型
jack.setT(18.0);//ok
// jack.setT(18);//报错,
Person mark = new Person<>("Mark");//ok
mark.setT("hello");//ok,默认都是Object,hello是String,String是Object的子类
}
}
class Person<T,R,M>{
private String name;
T t;
R r;
M m;
public Person(String name) {
this.name = name;
}
public Person(T t, R r, M m) {
this.t = t;
this.r = r;
this.m = m;
}
public void setT(T t) {
this.t = t;
}
public void setR(R r) {
this.r = r;
}
public void setM(M m) {
this.m = m;
}
}
13.2.2 自定义泛型接口
- 基本语法
interface 接口名<T,R..>{}
- 注意细节
(1). 接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
(2). 泛型接口的类型,在继承接口或者实现接口时确定
(3). 没有指定类型,默认为Object
package chapter13.customgeneric;
/**
* @aim java基础学习
* @note java笔记
*/
public class CustomInterfaceGeneric {
public static void main(String[] args) {
}
}
/**
* 1.接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
* 2.泛型接口的类型,在继承接口或者实现接口时确定
* 3.没有指定类型,默认为Object
*/
//在继承接口时,直接确定泛型接口的类型
interface IA extends IUsb<String ,Double>{}
//当实现IA这个接口时,因为IA在继承IUsb接口时,指定了 U=String, R=Double
//所以在A实现IA接口既要实现IA的抽象方法,也要实现IUub的抽象方法。
// 在使用快捷键实现IUsb的方法时会把String自动替换为U,Double自动替换为R
class A implements IA{
@Override
public Double get(String s) {
return null;
}
@Override
public void hi(Double aDouble) {
}
@Override
public void run(Double r1, Double r2, String u1, String u2) {
}
}
//在实现接口时,直接指定泛型接口的类型
//即U 指定了Integer R指定了Float
//所以,当实现IUsb的方法时,会使用Integer替换U, 使用Float替换R
class B implements IUsb<Integer,Float>{
@Override
public Float get(Integer integer) {
return null;
}
@Override
public void hi(Float aFloat) {
}
@Override
public void run(Float r1, Float r2, Integer u1, Integer u2) {
}
}
//没有指定类型,默认为Object,但不推荐不写,建议即使不指定也要加上<Object,Object>
class C implements IUsb{//等价于class C implements IUsb<Object,Object>{}
@Override
public Object get(Object o) {
return null;
}
@Override
public void hi(Object o) { }
@Override
public void run(Object r1, Object r2, Object u1, Object u2) {
}
}
interface IUsb<U,R>{
static int i=10;
// static U u="hello";//报错
//普通方法中,可以使用泛型接口
R get(U u);
void hi(R r);
void run(R r1,R r2,U u1,U u2);
//在jdk8中,可以在接口中使用默认方法
default R method(U u){
return null;
}
}
13.2.3 自定义泛型方法
- 基本语法
修饰符 <T,R..> 返回类型 方法名(参数列表){}
- 注意细节
(1). 泛型方法,可以定义在普通类中,也可以定义在泛型类中
(2). 当泛型方法被调用时,类型会确定
(3). Public void eat(E e){}不是泛型方法,而是使用了泛型。因为修饰符后没有<T,R…> eat方法不是泛型方法。
package chapter13.customgeneric;
import java.util.ArrayList;
/**
* @aim java基础学习
* @note java笔记
*/
public class CustomMethodGeneric {
public static void main(String[] args) {
Car car = new Car();
car.fly("horse",2000);//当调用方法时,插入参数,编译器就会确定类型(如果是基本数据类型会自动装箱)
//class java.lang.String
//class java.lang.Integer
Fish<String, ArrayList> fish = new Fish<>();
fish.hello(new ArrayList(),100.3f);
//class java.util.ArrayList
//class java.lang.Float
}
}
class Car{//普通类
public void run(){//普通方法
}
//1.<T,R>就是泛型
//2.是提供给福利院使用的
public <T,R> void fly(T t,R r){//泛型方法.当泛型方法被调用时,类型会确定
System.out.println(t.getClass());
System.out.println(r.getClass());
}
}
class Fish<T,R>{//泛型类
public void run(){//普通方法
}
public <U,M>void eat(U u,M m){//泛型方法
}
//下面的hi方法不是泛型方法,只是使用了类声明的泛型而已
public void hi(T t){}
//泛型方法,可以使用类声明的泛型,也可以使用自己声明泛型
public <K> void hello(R r,K k){
System.out.println(r.getClass());
System.out.println(k.getClass());
}
}
- 自定义泛型方法练习
判断下面代码是否正确,如果有错误,修改正确,并说明输出什么?
package chapter13.customgeneric;
/**
* @aim java基础学习
* @note java笔记
*/
public class CustomMethodGenericExercise {
public static void main(String[] args) {
Apple<String,Integer,Double> apple = new Apple<>();
apple.fly(10);//Integer
apple.fly(new Dog());//Dog
}
}
class Apple<T,R,M>{
public <E> void fly(E e){
System.out.println(e.getClass().getSimpleName());
}
// public void eat(U u){}//报错,因为泛型U没有声明
public void run(M m){}
}
class Dog{ }
13.3 泛型继承和通配符
- 泛型的基础和通配符说明
(1). 泛型不具备继承性
List list = new ArrayList(); //对吗
(2). <?>:表示支持任意泛型类型
(3). <? extends A>:支持A类以及A类的子类,规定了泛型的上限。
(4). <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。
(4). <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。
package chapter13.extendsgeneric_;
import java.util.ArrayList;
import java.util.List;
/**
* @aim java基础学习
* @note java笔记
*/
public class ExtendsGeneric_ {
public static void main(String[] args) {
Object o = new String("hello");
// List<Object> list = new ArrayList<String>(); //对吗,不对泛型没有继承关系
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<A> list3 = new ArrayList<>();
List<B> list4 = new ArrayList<>();
List<C> list5 = new ArrayList<>();
//(2). <?>:表示支持任意泛型类型
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
//(3). <? extends A>:支持A类以及A类的子类,规定了泛型的上限。
// printCollection2(list1);//报错
// printCollection2(list2);//报错
printCollection2(list3);
printCollection2(list4);
printCollection2(list5);
//(4). <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。
printCollection3(list1);
// printCollection3(list2);//报错
// printCollection3(list3);//报错
// printCollection3(list4);//报错
// printCollection3(list5);//报错
}
//(2). <?>:表示支持任意泛型类型
public static void printCollection1(List<?> c) {
for (Object o : c) {
System.out.println(o);
}
}
//(3). <? extends A>:支持A类以及A类的子类,规定了泛型的上限。
public static void printCollection2(List<? extends A> c) {
for (Object o : c) {
System.out.println(o);
}
}
//(4). <? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限。
public static void printCollection3(List<? super A> c) {
for (Object o : c) {
System.out.println(c);
}
}
}
class A {
}
class B extends A {
}
class C extends B {
}
13.4 JUnit
- 为什么需要Junit
(1). 一个类中有很多功能代码需要测试,为了测试,就需要写入到main方法中
(2). 如果有多个功能代码测试,就需要来回注销,切换很麻烦
(3). 如果可以直接运行一个方法,就方便很多,并且可以给出相关信息,就好了 - 基本介绍
(1). Junit是一个java语言的单元测试框架
(2). 多数java的开发环境都已经集成了Junit作为单元测试的工具
package chapter13;
import org.junit.jupiter.api.Test;
/**
* @aim java基础学习
* @note java笔记
*/
public class JUnit_ {
public static void main(String[] args) {
//传统方法的测试调用
//先测试m1
// new JUnit_().m1();
//为了测试m2,有时候会把m1的调用注销或加上注释不影响其他功能的测试
// new JUnit_().m2();
//所以就有JUnit测试框架
}
//写两个方法测试输出
@Test
public void m1(){
System.out.println("m1 方法被调用");
}
public void m2(){
System.out.println("m2 方法被调用");
}
}
- 如何添加Junit
在需要运行功能的地方打上@Test,然后将光标放到Test上快捷键alt+enter。然后下载即可。具体图片如下:
4. 添加完Junit的好处
添加完Junit,在某个功能的上面添加@Test,就可以单独运行某个功能,既不用写到main方法中,也不影响其他的运行。
13.5 本章作业
- 编程题
(1). 定义一个泛型类DAO,在其中定义一个Map成员变量,Map的键为String类型,值为T类型。分别创建以下方法:
① public void save(String id,T entity):保存T类型的对象到Map成员变量中
② public T get(String id):从map中获取id对应的对象
③ public void update(String id, T entity):替换map中的key为id的内容,改为entity对象
④ public List list():返回map中存放的所有T对象
⑤ public void delete(String id):删除指定id对象
(2). 定义一个User类:该类包含:private成员变量(int类型) id , age;(String)name
(3). 创建DAO类的对象,分别调用其save、get、update、list、delete方法来操作User对象(也就是T=User),使用Junit单元测试框架进行测试
- User类
package chapter13.task_;
/**
* @aim java基础学习
* @note java笔记
*/
public 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 int getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
- DAO类
DAO类
package chapter13.task_;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @aim java基础学习
* @note java笔记
*/
public class DAO <T>{
private Map<String,T> map=new HashMap<>();
//保存T类型的对象到Map成员变量中
public void save(String id,T entity){
map.put(id,entity);
}
//从map中获取id对应的对象
public T get(String id){
return map.get(id);
}
//替换map中的key为id的内容,改为entity对象
public void update(String id,T entity){
map.put(id,entity);
}
//返回map中存放的所有T对象
public List<T> list(){
List<T> list = new ArrayList<>();
for (String key : map.keySet()) {
list.add(get(key));
}
return list;
}
//删除指定id对象
public void delete(String id){
map.remove(id);
}
}
- Task01测试类
package chapter13.task_;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* @aim java基础学习
* @note java笔记
*/
public class Task01 {
public static void main(String[] args) {
}
@Test
public void testing(){
DAO<User> dao = new DAO<>();
dao.save("001",new User(1,19,"mark"));
dao.save("002",new User(2,15,"rose"));
dao.save("003",new User(3,12,"lucy"));
System.out.println(dao.get("001"));//User{id=1, age=19, name='mark'}
dao.update("003",new User(3,10,"jack"));
dao.delete("001");
List<User> list = dao.list();
System.out.println(list);
//[User{id=2, age=15, name='rose'}, User{id=3, age=10, name='jack'}]
}
}