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 + '\'' +
            '}';
}

}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值