• Java中的泛型


    目录

    一、什么是泛型

    (1)、 解释:

    (2)、语法:

    二、泛型类的使用

    三、擦除机制

    注意:

    四、泛型的上界

    (1)、语法

    (2)、示例

    (3)、复杂示例

    ​编辑

    五、泛型的方法

    (1)、语法

    (2)、示例

    六、通配符

    (1)、通配符解决什么问题

    (2)、通配符的上界

    (3)、通配符的下届

    都看到这里了,点个赞再走吧,谢谢谢谢谢!!!


    一、什么是泛型

    (1)、 解释:

            一般的类和方法,只能使用具体类型,要么是基本类型,要么是自定义类型,如果我们要编写可以应用多种类型的的代码就能使用到泛型

    (2)、语法:

            

    代码示例:

    1. class MyArray {
    2. public T[] array = (T[])new Object[10];
    3. public T getPos(int pos) {
    4. return this.array[pos];
    5. }
    6. public void setVal(int pos, T val) {
    7. this.array[pos] = val;
    8. }
    9. }
    10. public class Test {
    11. public static void main(String[] args) {
    12. MyArray myArray = new MyArray<>();
    13. myArray.setVal(0, 10);
    14. myArray.setVal(1, 20);
    15. int ret = myArray.getPos(0);
    16. System.out.println(ret);//输出10
    17. }
    18. }

    代码解释:类名后的 代表占位符,表示当前类是一个泛型类


    二、泛型类的使用

    语法:

    注意:泛型的使用只能接受类,所以基本数据类型必须使用包装类

    如下图:

    我们也可以写成如下形式:

    编译器可以根据上下文推导出类型的实参,可以省略类型的实参。


    三、擦除机制

    Java的泛型机制是在编译级别实现的,将所有T替换成Object这种机制我们称为擦除机制。

    (代码是上面的代码)通过命令:javap -c 查看字节码文件,所有的T都是Object

    注意:

            泛型类不能实例化,演示代码如下:

    1. class MyArray {
    2. public T[] array = (T[])new Object[10];
    3. public T getPos(int pos) {
    4. return this.array[pos];
    5. }
    6. public void setVal(int pos, T val) {
    7. this.array[pos] = val;
    8. }
    9. public T[] getArray() {
    10. return this.array;
    11. }
    12. }
    13. public static void main(String[] args) {
    14. MyArray myArray = new MyArray<>();
    15. Integer[] array = myArray.getArray();
    16. }

    运行代码时会报错,报错结果如下:

    原因:

    因为擦除机制在编译时将所有的T类型都转换为Object类型,所以调用getArray方法是拿到的是Object类型,而不是Integer类型将Object[]分配给Integer[]引用,是不安全的,程序会报错;

    通俗的来讲,因为Object默认是任何类型的父类,可以存放任何类型可能是String,可能是Person,运行时直接把Object传给Integer类型的数组,编译器认为是不安全的。


    四、泛型的上界

    (1)、语法

    (2)、示例

    而调用MyArray,E的类型,我们可以传入Number,也可以传入Number的子类。

    (3)、复杂示例

    E必须是实现了Comparable接口的类型。


    五、泛型的方法

    (1)、语法

    (2)、示例

    代码如下:

    1. public class Test {
    2. public static void swap(E[] array, int i, int j) {
    3. E t = array[i];
    4. array[i] = array[j];
    5. array[j] = t;
    6. }
    7. public static void main(String[] args) {
    8. Integer[] array = {1,2,3,4,5};
    9. System.out.println(Arrays.toString(array));
    10. //不使用类推到
    11. Test.swap(array, 0, 1);
    12. System.out.println(Arrays.toString(array));
    13. System.out.println("==============");
    14. //使用使用类推到
    15. swap(array, 0, 1);
    16. System.out.println(Arrays.toString(array));
    17. }
    18. }

    执行代码结果如下:

    六、通配符

    (1)、通配符解决什么问题

    代码示例:

    1. class Message {
    2. private T message ;
    3. public T getMessage() {
    4. return message;
    5. }
    6. public void setMessage(T message) {
    7. this.message = message;
    8. }
    9. }
    10. public class TestDemo {
    11. public static void main(String[] args) {
    12. Message message = new Message<>() ;
    13. message.setMessage("hello world");
    14. fun(message);
    15. }
    16. public static void fun(Message temp){
    17. System.out.println(temp.getMessage());
    18. }

    上述程序带来了新的问题,如果泛型设置的不是String类,而是Integer类呢

    我们想让fun能接受所有泛型类型,但又不能更改fun的形参类型,这时候就可以用到通配符

    通配符的使用如下:

    (2)、通配符的上界

    语法:

    代码示例:

    1. class Food {
    2. }
    3. class Fruit extends Food {
    4. }
    5. class Apple extends Fruit {
    6. }
    7. class Banana extends Fruit {
    8. }
    9. class Message {
    10. private T message;
    11. public T getMessage() {
    12. return message;
    13. }
    14. public void setMessage(T message) {
    15. this.message = message;
    16. }
    17. }
    18. public class Test2 {
    19. public static void main(String[] args) {
    20. Message message1 = new Message<>();
    21. message1.setMessage(new Fruit());
    22. fun(message1);
    23. Message message2 = new Message<>();
    24. message2.setMessage(new Banana());
    25. fun(message2);
    26. Message message3 = new Message<>();
    27. message3.setMessage(new Food());
    28. //fun(message3);//err
    29. }
    30. public static void fun(Message tmp) {
    31. System.out.println(tmp.getMessage());
    32. }
    33. }

    由上述例子我们可以看出,我们想调用fun方法,传入的参数的类型必须是Fruit或者是Fruit的子类,不然会报错

    此时无法在fun函数中对temp进行添加元素,因为temp接收的是Fruit和他的子类,此时存储的元素应该是哪个子类无法确定。所以添加会报错!但是可以获取元素。
     

    (3)、通配符的下届

    语法:

    1. class Food {
    2. }
    3. class Fruit extends Food {
    4. }
    5. class Apple extends Fruit {
    6. }
    7. class Banana extends Fruit {
    8. }
    9. class Message {
    10. private T message;
    11. public T getMessage() {
    12. return message;
    13. }
    14. public void setMessage(T message) {
    15. this.message = message;
    16. }
    17. }
    18. public class Test2 {
    19. public static void main(String[] args) {
    20. Message message1 = new Message<>();
    21. message1.setMessage(new Fruit());
    22. fun2(message1);
    23. Message message2 = new Message<>();
    24. message2.setMessage(new Food());
    25. fun2(message2);
    26. Message message3 = new Message<>();
    27. message3.setMessage(new Apple());
    28. //fun2(message3);//err
    29. }
    30. public static void fun2(Messagesuper Fruit> tmp) {
    31. System.out.println(tmp.getMessage());
    32. }
    33. }

    调用fun2方法时,我们传入的类型只能是Fruit类或者Fruit的父类,不然会报错

    通配符的下界,不能进行读取数据,只能写入数据
     


    都看到这里了,点个赞再走吧,谢谢谢谢谢!!!

  • 相关阅读:
    RecycleView实现item重叠水平滑动
    第一章初识微服务
    Mybatis-Plus批量插入应该怎么用
    【docker】学习笔记
    sklearn.preprocessing.StandardScaler¶
    mlflow详细安装部署
    数据仓库之数据冗余规范
    如何使用 FaceIO 在 Vue.JS 中实现人脸识别?
    【Linux】《Linux命令行与shell脚本编程大全 (第4版) 》笔记-Chapter6-Linux 环境变量
    PG-PFC-17E、PG-PEV-16A、PG-PEV-18A插装式比例流量阀控制器
  • 原文地址:https://blog.csdn.net/cool_tao6/article/details/134074500