java第十五章:泛型
java第十五章:泛型
泛型
传统方法问题分析
- 不能对加入到集合ArrayList中的数据类型进行约束(不安全)
- 遍历时,需要进行类型转换,如果集合中数据量较大,效率低
泛型好处:
- 编译时,检查添加元素的类型,提高安全性
- 减少了类型转换的次数,提高效率
不使用泛型:
Dog - 加入 - > Object - 取出 - > Dog
使用泛型:
Dog - 加入 - > Dog - 取出 - > Dog
- 不再提示编译警告(不使用泛型:存在编译警告,因为存在报ClassCastException异常的风险)
泛型介绍:
泛型:广泛类型 => Integer、String、Dog
1.泛型又称参数化类型,解决数据类型的安全性问题
2.保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
3.作用:
在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型
泛型举例:
package com.lcz.generic;
import java.util.*;
/**
* @author lcz
* @version 1.0
* 需求:
* 泛型举例使用
* 1.创建3个对象
* 2.将学生对象放入到HashSet中
* 3.放入到HashMap中,要求Key是String name、Value是学生对象
* 4.使用两种方式遍历
*/
public class Generic {
public static void main(String[] args) {
//1.HashSet
HashSet<Student> students = new HashSet<>();
students.add(new Student("lhc",24));
students.add(new Student("lcz",20));
students.add(new Student("wdm",20));
//迭代器遍历
System.out.println("迭代器遍历");
Iterator<Student> iterator = students.iterator();
while (iterator.hasNext()) {
Student student = iterator.next();
System.out.println(student);
}
//增强for
System.out.println("增强for");
for (Student student :students) {
System.out.println(student);
}
//2.HashMap
HashMap<String, Student> hm = new HashMap<>();
hm.put("lhc",new Student("lhc",24));
hm.put("lcz",new Student("lcz",20));
hm.put("wdm",new Student("wdm",20));
//获取entry集合
Set<Map.Entry<String, Student>> entries = hm.entrySet();
//迭代器遍历
System.out.println("迭代器遍历");
Iterator<Map.Entry<String, Student>> iterator1 = entries.iterator();
while (iterator1.hasNext()) {
Map.Entry<String, Student> student = iterator1.next();
System.out.println(student);
}
//增强for
System.out.println("增强for");
for (Map.Entry entry :entries) {
System.out.println(entry.getKey() + " : " + entry.getValue());
}
}
}
class Student{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
泛型细节:
1.泛型只能为引用类型,不能为基本数据类型
2.在给泛型指定具体类型后,可以传入该类型或者其子类类型
3.泛型使用形式:
传统:List<Integer> list1 = new ArrayList<Interger>();
简洁(推荐):List<Integer> list1 = new ArrayList<>();
4.如果这样写:List list3 = new ArrayList(); 默认给他的泛型是Object
泛型语法:
interface 接口<T>{} 和 class 类<K,V>{}
如:
List<String> list1 = new ArrayList<>();
Iterator<Customer> iterator = customers.iterator();
泛型课堂练习:
package com.lcz.generic;
import java.time.Year;
import java.util.ArrayList;
import java.util.Comparator;
/**
* @author lcz
* @version 1.0
* 需求:
* 1.定义Employee类,包含:name、sal、birthday,其中birthday为MyDate类的对象;
* 2.为每个属性定义getter、setter方法
* 3.重写toString方法
* 4.MyDate类包含:year、month、day,并为每个属性定义getter、setter方法
* 5.创建该类的3个对象,放入ArrayList(使用泛型来定义)中,对集合中元素进行排序,并遍历输出
* 排序方式:定制排序:先按照name排序,若name相同,按生日日期先后排序
*/
public class GenericExer01 {
public static void main(String[] args) {
ArrayList<Employee> employees = new ArrayList<>();
employees.add(new Employee("lhc",20000,new MyDate1(2000,11,30)));
employees.add(new Employee("lhc",10000,new MyDate1(2000,11,27)));
employees.add(new Employee("b",1050,new MyDate1(2004,12,15)));
employees.sort(new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if(!(o1.getName().equals(o2.getName())))
return o1.getName().compareTo(o2.getName());
else{
//年月日比较由MyDate类实现Comparable接口(指定泛型)完成
return o1.getBirthday().compareTo(o2.getBirthday());
}
}
});
for (Employee employee :employees) {
System.out.println(employee);
}
}
}
class Employee{
private String name;
private double sal;
private MyDate1 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 MyDate1 getBirthday() {
return birthday;
}
public void setBirthday(MyDate1 birthday) {
this.birthday = birthday;
}
public Employee(String name, double sal, MyDate1 birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate1 implements Comparable<MyDate1>{
private int year;
private int month;
private int day;
public MyDate1(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
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;
}
@Override
public String toString() {
return "MyDate1{" +
"year=" + year +
", month=" + month +
", day=" + day +
'}';
}
@Override
public int compareTo(MyDate1 o) {//将年月日比较封装到MyDate类的Comparable接口中
if(!(year == o.getYear())){
return year - o.getYear();
}
if(!(month == o.getMonth())){
return month - o.getMonth();
}
else {
return day - o.getDay();
}
}
}
自定义泛型
自定义泛型类
语法:
class 类名<T,R...>{//...表示可以有多个泛型
成员
}
细节:
1.普通成员可以使用泛型(属性、方法)
2.使用泛型的数组,不能初始化
因为数组在new 不能确定T的类型,就无法在内存开辟空间
3.静态方法中不能使用类的泛型
因为静态是和类相关的,在类加载时,对象还没有创建
所以,如果静态方法和静态属性使用了泛型,JVM就无法完成初始化
4.创建对象时需指定泛型类的类型
若没有指定,默认为Object
package com.lcz.generic.customgeneric;
import java.util.ArrayList;
/**
* @author lcz
* @version 1.0
* 需求:
* 自定义泛型类
*
*/
public class CustomGeneric {
public static void main(String[] args) {
A<String, Integer, Double> lhc = new A<String, Integer, Double>("lhc", 24, 2000.0);
System.out.println(lhc);
}
}
class A<T,R,M>{
private T t;//属性使用泛型
private R r;
private M m;
public A(T t, R r, M m) {//参数使用泛型
this.t = t;
this.r = r;
this.m = m;
}
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;
}
@Override
public String toString() {
return "A{" +
"t=" + t +
", r=" + r +
", m=" + m +
'}';
}
}
自定义泛型接口
语法:
interface 接口名<T,R...>{
}
细节:
1.静态成员不能使用泛型
2.泛型接口的类型,在继承接口或者实现接口时确定
3.没有指定类型,默认为Object
package com.lcz.generic.customgeneric;
/**
* @author lcz
* @version 1.0
* 需求:
* 自定义泛型接口
*/
public class CustomGeneric01 {
public static void main(String[] args) {
}
}
interface IUsb<T,R>{
void f1(T t,R r);
}
interface IA extends IUsb<String,Integer>{
}
class A1 implements IUsb<String,Double>{
@Override
public void f1(String s, Double aDouble) {
}
}
class B1 implements IA{
@Override
public void f1(String s, Integer integer) {
}
}
接口和抽象类区别:
接口:
//接口权限和类一样,public或者默认
//接口中可以包含属性,方法:静态方法、默认方法、抽象方法
//属性默认都是public static final
//默认方法用default声明
//静态方法用static声明
//普通方法默认public abstract即抽象方法
//所以接口中既可以有抽象方法,也可以有具体方法的实现
抽象类:
//类需要abstract声明
//既可以有普通属性又可以有静态属性
//既可以有普通方法又可以有静态方法
泛型方法
语法:
修饰符<T,R...> 返回类型 方法名(参数列表){
}
细节:
1.泛型方法,可以定义在普通类中,也可以定义在泛型类中
2.当泛型方法被调用时,类型也会确定
3.public void eat(E e){},修饰符后没有<T,R...>,eat方法不是泛型方法,而是使用了泛型
package com.lcz.generic.customgeneric;
/**
* @author lcz
* @version 1.0
* 需求:
* 自定义泛型方法
*/
public class CustomGeneric03 {
public static void main(String[] args) {
new C().f1("saf",10);
System.out.println("=====");
new C().f1('f',10.0);
}
}
class C{
public <T,R> void f1(T t,R r){
System.out.println(t.getClass().getSimpleName());
System.out.println(r.getClass().getSimpleName());
}
}
泛型的继承和通配符
细节:
1.泛型不具备继承性
ArrayList<Object> alt = new ArrayList<String>()//不具备继承性,会报错
2.<?>:支持任意泛型类型
3.<? extends A>:支持A类以及A类的子类,规定了泛型的上限
4.<? super A>:支持A类以及A类父类,规定了泛型的下限
package com.lcz.generic.customgeneric.extend;
import org.junit.jupiter.api.Test;
import java.util.ArrayList;
import java.util.List;
/**
* @author lcz
* @version 1.0
* 需求:
* 泛型的继承和通配符
*/
public class Extends_ {
public static void main(String[] args) {
ArrayList<String> strings = new ArrayList<>();
ArrayList<Integer> integers = new ArrayList<>();
ArrayList<AA> aas = new ArrayList<>();
ArrayList<BB> bbs = new ArrayList<>();
ArrayList<CC> ccs = new ArrayList<>();
printCollection1(aas);
}
public static void printCollection(List<?> c){
for (Object o :c) {
System.out.println(o);
}
}
public static void printCollection1(List<? extends AA> c){
for (Object o :c) {
System.out.println(o);
}
}
public static void printCollection2(List<? super AA> c){
for (Object o :c) {
System.out.println(o);
}
}
}
class AA{
}
class BB extends AA{
}
class CC extends BB{
}
JUnit:单元测试框架
介绍:
1.JUnit是一个java语言的单元测试框架
2.多数java的开发环境都已经集成了JUnit作为单元测试的工具
使用:
1.加一个@Test
2.Alt + Enter 添加JUnit5.4 即可单独运行测试该方法
package com.lcz.generic.customgeneric.JUnit;
import org.junit.jupiter.api.Test;
/**
* @author lcz
* @version 1.0
*/
public class JUnit {
public static void main(String[] args) {
}
@Test
public void m1(){
System.out.println("m1被调用");
}
@Test
public void m2(){
System.out.println("m2被调用");
}
}
本章作业:
package com.lcz.generic.customgeneric.homework;
import org.junit.jupiter.api.Test;
import java.util.*;
/**
* @author lcz
* @version 1.0
* 需求:
* 定义一个泛型类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类:
* 包含: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 testList(){
DAO<User> userDAO = new DAO<User>();
userDAO.save("1",new User(1,24,"lhc"));
System.out.println(userDAO.get("1"));
userDAO.update("1",new User(2,20,"lcz"));
List<User> list = userDAO.list();
for (User user :list) {
System.out.println(user);
}
userDAO.delete("1");
}
}
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.put(id,entity);
}
public List<T> list(){
Collection<T> values = map.values();
return new ArrayList<>(values);
}
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 "User{" +
"id=" + id +
", age=" + age +
", name='" + name + '\'' +
'}';
}
}
r(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 + '\'' +
'}';
}
}