P554~P568
使用传统方法的问题
- 不能对加入到集合ArrayList中的数据类型进行约束
- 遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响
泛型的好处
- 编译时,检查添加元素的类型,提高了安全性
- 减少了类型转换的次数,提高效率
- 不再提示编译警告
泛型,Generic01.java
- 泛型又称参数化类型,解决数据类型的安全性问题
- 在类声明或实例化时,只要指定好需要的具体类型即可
- java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常
- 泛型作用:可以在类声明时通过一个标识表示类中某个属性的类型,或是某个方法的返回值的类型,或者是参数类型
import java.util.ArrayList;
public class Generic01 {
public static void main(String[] args) {
ArrayList<Dog13> dogs = new ArrayList<>();
dogs.add(new Dog13("aa",10));
dogs.add(new Dog13("bb",10));
dogs.add(new Dog13("cc",10));
}
}
class Dog13<E>{
E e;//在定义Person对象的时候指定,即在编译期间,就确定E是什么类型
private String name;
private int age;
public Dog13(E e) {
this.e = e;
}
public E f(){
return e;
}
public Dog13(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;
}
}
泛型的声明
interface 接口<T>{}
class 类<K,V>{}
- T、K、V不代表值,而是表示类型
- 任意字母都可以,T-Type
泛型实例化
List<String> strList = new ArrayList<String> ();
Iterator<Customer> iterator = customers.iterator();
泛型语法使用,GenericExercise.java
- 创建3个学生对象
- 放入HashSet中
- 放入HashMap中,要求Key是String name,Value是学生对象
- 使用两种遍历方式
import java.util.*;
public class GenericExercise {
public static void main(String[] args) {
HashSet<Student> students = new HashSet<>();
students.add(new Student("jack1", 18));
students.add(new Student("jack2", 18));
students.add(new Student("jack3", 18));
for (Student student : students) {
System.out.println(student);
}
HashMap<String, Student> stringStudentHashMap = new HashMap<>();
stringStudentHashMap.put("jack1", new Student("jack1", 10));
stringStudentHashMap.put("jack2", new Student("jack2", 10));
stringStudentHashMap.put("jack3", new Student("jack3", 10));
Set<Map.Entry<String, Student>> entries = stringStudentHashMap.entrySet();
Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Student> next = iterator.next();
System.out.println(next);
}
}
}
class Student {
private String name;
private int age;
public Student(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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
使用细节
- 在指定泛型具体类型后,可以传入该类型或者其子类类型
- 泛型使用形式
List<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<>();
List list3 = new ArrayList();
默认泛型类型是Object
泛型课堂练习,GenericExercise02.java
定义Employee类
- 该类包含:private成员变量 name,sal,birthday,其中birthday为MyDate类的对象
- 为每一个属性定义getter,setter方法
- 重写toString方法输出name,sal,birthday
- MyDate类包含:private成员变量month、day、year,并为每个属性定义getter、setter方法
- 创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList用泛型来定义),对集合中的元素进行排序,并遍历输出
排序方式:用ArrayList的sort方法,传入Comparator对象(使用泛型),先按照name排序,如果name相同则按生日日期先后排序
import java.util.*;
public class GenericExercise02 {
public static void main(String[] args) {
ArrayList<Employee13> employees = new ArrayList<>();
employees.add(new Employee13("jack2",100.20,new MyDate(2010,8,2)));
employees.add(new Employee13("jack3",100.10,new MyDate(2010,8,1)));
employees.add(new Employee13("jack3",100.30,new MyDate(2010,8,3)));
employees.sort(new Comparator<Employee13>() {
@Override
public int compare(Employee13 o1, Employee13 o2) {
if(o1.getName().compareTo(o2.getName())!=0){
return o1.getName().compareTo(o2.getName());
}
return o1.getBirthday().compareTo(o2.getBirthday());
}
});
for (Employee13 next : employees) {
System.out.println(next);
}
}
}
//定义Employee13类
//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相同则按生日日期先后排序
class Employee13{
private String name;
private double sal;
private MyDate birthday;
public Employee13(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 "Employee13{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday.getYear() +birthday.getMonth()+birthday.getDay()+
'}';
}
}
class MyDate implements Comparable<MyDate>{
private int month;
private int day;
private int year;
public MyDate(int year, int month, int day) {
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 int compareTo(MyDate o) {
int yearMinus=year-o.getYear();
if(yearMinus!=0){
return yearMinus;
}
int monthMinus=month-o.getMonth();
if(monthMinus!=0){
return monthMinus;
}
int dayMinus=day-o.getDay();
return dayMinus;
}
}
自定义泛型类,CustomGeneric.java
class 类名<T,R>{
成员
}
- 普通成员可以使用泛型,(属性、方法)
- 使用泛型的数组不能初始化
- 静态方法中不能使用类的泛型
- 泛型类的类型,是在创建对象时确定的,因为创建对象时,需要制定确定类型
- 如果在创建对象时,没有指定类型,默认为Object
public class CustomGeneric {
}
//TRM为泛型标识符,一般是单个大写字母
//泛型标识符可以有多个
//普通成员可使用泛型
class Tiger<T,R,M>{//自定义泛型类
String name;
T t;//属性使用泛型
R r;
M m;
// 2、数组在new时不能确定T的类型,就无法在内存开空间
// T[] tlist = new T[8];
// 3、静态方法不能使用类的泛型
// public static void m1(M m){
//
// }
// 在类加载时,对象还没创建
// 而泛型是类定义的时候才指定
// 所以如果静态方法、属性使用泛型,JVM就无法完成初始化
public Tiger(String name, T t, R r, M m) {//构造器使用泛型
this.name = name;
this.t = t;
this.r = r;
this.m = m;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public T getT() {
return t;
}
public void setT(T t) {//方法泛型
this.t = t;
}
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;
}
}
自定义泛型接口
interface 接口<T,R>{
}
- 接口中,静态成员也不能使用泛型
- 泛型接口的类型,在继承接口或实现接口时确定
- 没有指定类型,默认为Object
自定义泛型方法,MethodGeneric.java
修饰符 <T,R> 返回类型 方法名(参数列表){
}
- 泛型方法,可以定义在普通类中,也可以定义在泛型类中
- 当泛型方法被调用时,类型会确定
- public void eat(E e){},修饰符后没有<T,R…>eat方法不是泛型方法,而是使用了泛型
public class MethodGeneric {
public static void main(String[] args) {
Car car = new Car();
//当调用方法时,传入参数,编译器就会确定类型
//会自动装箱到包装类
car.fly("a", 100);
Fish<String, Integer> fish = new Fish<>();
fish.hello("Str", "hello");
}
}
class Car {//普通类
//普通方法
public void run() {}
//<T,R>就是泛型
//提供给fly使用
//泛型方法
public <T, R> void fly(T t, R r) {}
}
class Fish<T, R> {//泛型类
//普通方法
public void run() {}
//泛型方法
public <U, M> void swim(U u, M m) {}
//eat不是泛型方法,而是eat使用了类声明的泛型
public void eat(T t) {}
//泛型方法可以使用类声明的泛型,也可以使用自己声明的泛型
public <K> void hello(K k, T t) {}
}
泛型的继承和通配符,GenericExtend.java
-
泛型不具备继承性
List list = new ArrayList();//不允许
- <?>:支持任意泛型类型,?是通配符
- <? extends A>:支持A类及A类的子类,规定了泛型的上限
- <? super A>:支持A类及A类的父亲,不限于直接父类,规定了泛型的下限
public class GenericExtend {
public static void main(String[] args) {
Object o = new String("xx");
//说明下列三个方法的使用
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<AA> list3 = new ArrayList<>();
List<BB> list4 = new ArrayList<>();
List<CC> list5 = new ArrayList<>();
//<?>能够接受任意泛型类型
printCollection1(list1);
printCollection1(list2);
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
//List<? extends AA>,支持AA及其子类,不限于直接子类
printCollection2(list1);//Object不是AA的子类,错误
printCollection2(list2);//String不是AA子类,错误
printCollection2(list3);
printCollection2(list4);
printCollection2(list5);
//List<? super AA>,支持AA及其父类,不限于直接父类
printCollection3(list1);
printCollection3(list2);//String不是AA父类,错误
printCollection3(list3);
printCollection3(list4);//BB不是AA父类,错误
printCollection3(list5);//CC不是AA父类,错误
}
public static void printCollection1(List<?> c) {
}
public static void printCollection2(List<? extends AA> c) {
}
public static void printCollection3(List<? super AA> c){
}
}
class AA{}
class BB extends AA{}
class CC extends BB{}
本章作业,Homework1301.java
定义一个泛型类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对象
定义一个User类
包含:private成员变量(int类型)id,age;(String类型)name
创建DAO类的对象,分别调用方法来操作User对象,使用Homework1301测试类测试
import java.util.*;
public class Homework1301 {
public static void main(String[] args) {
DAO<User> userDAO = new DAO<User>();
userDAO.save("1",new User(1,10,"jack"));
userDAO.save("2",new User(2,20,"tom"));
userDAO.save("3",new User(3,30,"mary"));
System.out.println(userDAO.get("1"));
userDAO.update("1",new User(1,10,"jackyyy"));
System.out.println(userDAO.get("1"));
for (Object o :userDAO.list()) {
System.out.println(o);
}
userDAO.delete("2");
for (Object o :userDAO.list()) {
System.out.println(o);
}
}
}
//定义一个泛型类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对象
class DAO<T> {
public 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.put(id,entity);
}
public List<T> list(){
List<T> ts = new ArrayList<>();
for (Map.Entry<String, T> next : map.entrySet()) {
ts.add(next.getValue());
}
return ts;
}
public void delete(String id){
map.remove(id);
}
}
//包含:private成员变量(int类型)id,age;(String类型)name
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 "User{" +"id=" + id +", age=" + age +", name='" + name + '\'' +'}';
}
}