JavaSE --- 泛型

1.了解基础

  1. 概述

  1. 编译阶段就会约束操作的数据类型,便于检查

  1. 格式:

<数据类型>

注意:数据类型只能填写引用数据类型,泛型也只支持引用数据类型。

  1. 集合体系的全部接口和实现类都支持泛型的使用

2.优点

  1. 统一数据类型

  1. 把运行时期的问题提前到编译时期,避免了强制类型转换可能出现的异常

这样说可能会笼统,用代码演示解释

import java.util.ArrayList;
import java.util.List;

public class GenericityDemo {
    public static void main(String[] args) {
        //好处1:
        //创建一个有泛型的集合,数据约束为字符串
        List<String> list1 = new ArrayList<>();
        //向集合中添加字符串的元素不会报错
        list1.add("Hadoop");
        list1.add("Spark");
        list1.add(23.3); //一旦添加非字符串的元素就会直接标红
        list1.add(10);

        //好处2:
        //防止了强制数据类型出现错位于
        //例子
        //定义普通的集合
        List list2 = new ArrayList();
        list2.add("Hadoop");
        list2.add("Spark");
        list2.add(23.3);
        list2.add(10);

        for (Object o : list2) {
            //未带泛型的集合直接强转数据类型编译时不会报错,运行时可能会报错
            String ele = (String) o;
            System.out.println(ele);
            //double 无法强转 String
            /**报错:Exception in thread "main" java.lang.ClassCastException:
                    java.lang.Double cannot be cast to java.lang.String
                       at com.hu.d8_genericity_class.GenericityDemo.main(GenericityDemo.java:29)
             */
        }

        //而使用了有泛型的集合,在编译阶段就已经规定了数据类型,根本就不需要强转
        for (String s : list1) {
            System.out.println(s);
        }
        //输出结果:
        //Hadoop
        //Spark

        //若真想填入任意类型,那么泛型可以使用Object
        List<Object> list3 = new ArrayList<>();
        list3.add("Hadoop");
        list3.add("Spark");
        list3.add(23.3);
        list3.add(10);
    }
}

3.泛型的定义范围

类后面 —— 泛型类

方法申明上 —— 泛型方法

接口后面 —— 泛型接口

2.自定义泛型

2.1泛型类

定义类时同时定义了泛型的类就是泛型类

泛型类的格式:

修饰符 class 类名<泛型变量>{}

//泛型变量可以写任何字母,但是为了专业点还是使用E、T、K、V作为变量

案例:模拟ArrayList集合自定义一个集合MyArrayList集合,完成添加和删除功能的泛型设计即可

MyArrayList

import java.util.ArrayList;

//定义MyArrayList的泛型设计
public class MyArrayList<E> {
    //扩展:因为我只是简单的定义泛型,并不可能真正实现输出存储到内存
    //所以我投机取巧:我直接用现有的ArrayList,调用人家已经写好的方法
    private ArrayList lists = new ArrayList();

    //添加增加元素功能,注意传入参数的数据类型是用E来表示了
    public void add(E e){
        //扩展内容
        lists.add(e);
    }

    //添加删除元素的功能
    public void remove(E e){
        //扩展内容
        lists.remove(e);
    }

    //扩展内容
    @Override
    public String toString() {
        return lists.toString();
    }
}

Text

public class Text {
    public static void main(String[] args) {
        //需求:模拟ArrayList定义一个MyArrayList,关注泛型设计
        //创建类的时候,限制了数据类型只能是字符串
        MyArrayList<String> list = new MyArrayList<>();
        //调用功能时候就只能出入的是字符串了
        list.add("Java");
        System.out.println(list.toString());
        list.remove("Java");

    }
}

总结:

泛型类的原理:就是把出现泛型变量的地方全部替换成传输的真实数据类型

2.2泛型方法

定义方法的同时定义了泛型的方法就是泛型方法

泛型方法格式

修饰符 <泛型变量> 方法返回值 方法名称(形参列表){}

注意

//在上面泛型类的例子中
public void add(E e){}
//这种并不是泛型方法,它的E是由泛型类定义的并非是它自己
//正确的是
public <T> void add(T t){}

泛型方法的作用:方法中可以使用泛型接收一切实际类型的参数,方便更具有通用性

案例:给定一个任意类型的数组,都能返回它的内容

public class GenericDemo {
    public static void main(String[] args) {
        String[] name = {"hadoop", "spark", "java"};
        printArray(name);
    }

    //定义泛型方法
    public static <T> void printArray(T[] arr){
        StringBuilder sb = new StringBuilder("[");
        if (arr != null)    {
            for (int i =0; i < arr.length; i++) {
                sb.append(arr[i]).append(i == arr.length - 1 ? "" : ", ");
            }
            sb.append("]");
            System.out.println(sb);
        }else {
            System.out.println(arr);
        }
    }
}

2.3泛型接口

使用了泛型定义的接口就是泛型接口

泛型接口格式

修饰符 interface 接口名称<泛型变量>{}
//实例
public interface Data<E>{}

泛型接口的作用:泛型接口可以让实现类选择当前功能需要操作的数据类型

案例:在一个教务系统中,定义一个接口,该接口可以约束一定要完成的数据(学生,老师)的增加和更新操作

学生类

public class Student {
}

老师类

public class Teacher {
}

接口

public interface Data<E> {
    //没有添加泛型的接口时的方法
    //void add(Student s);
    //void add(Teacher s);
    //可见不同的数据类型要重新定义方法,而添加了泛型之后就可以不用多次定义方法
    void add(E e);
    void updata(E e);
}

实现方法

//Data方法的实现了,泛型中指定的时Teacher数据类型
public class TeacherData implements Data<Teacher>{
    //重写的方法中的数据类型都是Teacher
    @Override
    public void add(Teacher teacher) {

    }

    @Override
    public void updata(Teacher teacher) {

    }
}

泛型接口的原理:实现类可以在实现接口的时候传入自己的数据操作的类型,这样重写的方法都将针对于该类型的操作。

3.泛型的通配符和上下限

3.1通配符:?

? 可以在“使用泛型”的时候代表一切类型。

而E T K V则时在定义的时候使用,并不是使用的时候用

案例

开发一个赛车游戏中,让所有的汽车都能比赛

public class GenericDemo {

    //方法:让所有汽车都能比赛
    //第一种:让宝马作为泛型数据变量
    //public static void go(ArrayList<BMW> cars){}
    //第二种:让父类作为泛型数据变量 原因是:虽然BMW和BENZ都继承了Car但是ArrayList<car>,ArrayList<BMW>, ArrayList<BENZ>没有任何关系,都是不同的集合
    //public static void go(ArrayList<car> cars){}
    //第三种:使用通配符
    public static void go(ArrayList<?> cars){}

    public static void main(String[] args) {
        //宝马车
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        //第一种:奔驰可以跑
        //第二种:谁都不能跑了
        //第三种:谁都可以跑了
        go(bmws);

        //奔驰车
        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        //第一种:但是奔驰车不能跑
        //第二种:谁都不能跑了
        //第三种:谁都可以跑了
        go(benzs);
    }
}

//奔驰车类
class BENZ extends Car{}
//宝马车类
class BMW extends Car{}
//汽车类父类
class Car{}

3.2上下限

依旧是上一个案例,如果我定义一个狗类,把狗放入到比赛能不能跑?

import java.util.ArrayList;

public class GenericDemo {

    public static void go(ArrayList<?> cars){}

    public static void main(String[] args) {
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

        //奔驰车
        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

        //狗开跑
        ArrayList<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        dogs.add(new Dog());
        dogs.add(new Dog());
        
        //发现dogs也能跑 这怎么能行
        go(dogs);

    }
}

//奔驰车类
class BENZ extends Car{}
//宝马车类
class BMW extends Car{}
//汽车类父类
class Car{}
//狗类
class Dog{}

发现狗也能跑,所以就由了通配符

? extends Car //表示 ? 必须是Car或者其子类 ———— 泛型的上限
? super Car   //表示 ? 必须是Car或者其父类 ———— 泛型的下限

修改后的代码

import java.util.ArrayList;

public class GenericDemo {
    //使用上下限后
    public static void go(ArrayList<? extends Car> cars){}

    public static void main(String[] args) {
        //宝马车
        ArrayList<BMW> bmws = new ArrayList<>();
        bmws.add(new BMW());
        bmws.add(new BMW());
        bmws.add(new BMW());
        go(bmws);

        //奔驰车
        ArrayList<BENZ> benzs = new ArrayList<>();
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        benzs.add(new BENZ());
        go(benzs);

        ArrayList<Dog> dogs = new ArrayList<>();
        dogs.add(new Dog());
        dogs.add(new Dog());
        dogs.add(new Dog());

        //发现dogs也能跑 这怎么能行
        //使用上下限后dogs就进不来了
        go(dogs);

    }
}

//奔驰车类
class BENZ extends Car{}
//宝马车类
class BMW extends Car{}
//汽车类父类
class Car{}
//狗类
class Dog{}

到这Java关于泛型的所有知识就说完了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值