【JavaSE】泛型

目录

▮ 为什么需要泛型?

▮泛型类

▪泛型类实例

▪泛型的规范​编辑

▮泛型的实现原理

▪擦除机制

▪泛型参数不能实例化(个人见解)

▮关于泛型的小细节

▪泛型参数不接受基本数据类型

▪省略类型参数传入

▪泛型参数不可实例化

▪泛型参数不可跟static同时出现

▮泛型方法

▪调用方法的实例

▪省略类型参数传入

▮泛型接口

▪调用实例


▮ 为什么需要泛型?

        有三种数组:int[ ], String[ ] , Animal[ ],分别是基本数据类型的数组,字符串数组,类数组。这三个数组的定义格式都是一样的,都是 “ 类型[ ] 引用 = new 类型[ ]{...};  ”。对于他们的共性部分,能不能提取出来?

        我能不能把“数据类型”作为参数?像方法那样的参数一般,传入到“定义格式”中。把数据类型作为参数传递,实现复用代码,降低耦合。


▮泛型类

▪泛型类实例

          •代码示例

class MyArray<E>{
    private E[] arr = (E[]) new Object[10];
    //返回一个数组引用
    public E[] getArray(){
        return arr;
    }
}

public class Main {
    public static void main(String[] args) {
        //传入类型Integer
        MyArray<Integer> array = new MyArray<>();
        //得到一个Integer[]
        Integer[] arr = array.getArray();
    }
}

        1.类名后多个<E>,<>是泛型的标志,E是类型参数

        2.引用arr的类型是 E[ ],new出的新对象转换成E[ ]

        3.泛型类实例化时,在类名后的<>传入类型

        4.泛型是类型参数化,处理的数据类型不再固定,可以作为参数传入

▪泛型的规范

         E本来只是一个参数名,没有什么特殊含义。但为了增加代码的可读性,Java规范了类型参数名,以及它对应的含义。


▮泛型的实现原理

▪擦除机制

        泛型是只存在于编译阶段的语法,在程序运行时,根本不知道有泛型这个东西的存在。因为在编译阶段,编译器会把所有的类型参数E给擦除,然后替换成Object,再加上必要的类型转换;所以在程序运行时,就只剩下强转(E)和Object了

▪泛型参数不能实例化(个人见解)

       • 泛型参数不能实例化,不是泛型类不能实例化

        一、因为泛型的实现机制就是强转Object,“new E[10]”,擦除后就变成了“new (E)Object[10]”。这是一个有问题的语法,因为还没new出对象就进行强转。

        二、泛型的本质就是依赖Object,那完全可以直接定义Object数组来进行操作,在最后需要数据时再添加类型转换。所以没必要去精准的定义泛型实例。

        •代码实例

/* Java中ArrayList泛型类的部分原码 */
public class ArrayList<E> {
    //一个Object数组
    Object[] elementData;

    //输出下标处的数据,返回值是E类型的,Object转成了E
    public E get(int index) {
        rangeCheck(index);//不用在意这个方法,它的作用是检查下标是否合法
        //调用了下方的方法
        return elementData(index);
    }
    
    //把对应下标的成员强转为E类型的数据
    E elementData(int index) {
        return (E) elementData[index];
    }
}

        这里的elementDate直接用Object来定义,没有使用泛型参数E。类里还有很多操作elementDate的方法,这些方法都是把它当作Object来处理。当外界要获取elemenDate时,再使用泛型参数E强转

        因为elementDate被封装,只能通过get()等方法被外界所调用,而这些方法都会对elementDate进行E类型转换。


▮关于泛型的小细节

▪泛型参数不接受基本数据类型

/* 错误示范 */
MyArray<int> array = new MyArray<int>();

        泛型参数可以传入类,也可以传入接口(接口本身就差不多等于类),但不能传入“int”这中基本数据类型。对此,Java中设有包装类来解决这个问题,实现基本数据类型向类类型的转换

▪省略类型参数传入

MyArray<Integer> array = new MyArray<Integer>();
//编译器可以根据前文推到出类型参数,所以省略了后面的<>里的内容
MyArray<Integer> array = new MyArray<>();

▪泛型参数不可实例化

         • 泛型参数不能实例化,不是泛型类不能实例化

/* 错误示范 */
private E[] arr = new E[10];

/* 正确写法 */
private E[] arr = (E[]) new Object[10];

▪泛型参数不可跟static同时出现

/* 错误示范 */
private static E[] arr = new E[10];

        "static T[]"是一个错误的用法,因为它违反了泛型的设计逻辑。static定义的代码只在程序中运行一次;而泛型可以传入不同类型,进行多次运行,创建多个对象。


▮泛型方法

//打印数组里的所有成员
public <E> void show(E[] arr){
    for(E a : arr){
        System.out.print(a + " ");
    }
    System.out.println();
}

        1.返回类型前加上<E>

        2.参数类型为<E>

▪调用方法的实例

public class Main {
    public static void main(String[] args) {
        Integer[] arr1 = new Integer[]{1,2,3,4};
        Character[] arr2 = new Character[]{'h','e','l','l','o'};
        Main main = new Main();
        main.show(arr1);
        main.show(arr2);
    }
    //打印数组里的所有成员
    public <E> void show(E[] arr){
        for(E a : arr){
            System.out.print(a + " ");
        }
        System.out.println();
    }
}

        •运行截图

▪省略类型参数传入

main.show(arr1);

        调用泛型方法时,可以不用手动传入类型,编译器会根据传入的实参自动传入类型。因为arr1的类型为Integer,所以自动传入了Integer。

▮泛型接口

public interface Comparable<T>{
    public int compareTO(T o);
}

public interface Comparator<T>{
    int compare(T o1,T o2);
    boolean equals(Object obj);
}

        1.接口名后有<>

        2.接口里的方法,返回类型前无<>,但参数还是T

▪调用实例

public class Main implements Comparator<Integer>{
    public static void main(String[] args) {
      Main test = new Main();
      if(test.compare(1,2) < 0){
          System.out.println("1 < 2");
      }
    }

    @Override
    public int compare(Integer o1, Integer o2) { //形参类型要跟传入泛型相同
        return o1 - o2;
    }
}

        当重写方法里的形参类型跟泛型相同时,方法才会构成重写。否则编译器就会报错,指出接口方法没有被重写。这里体现了泛型的起到的 “类型安全” 作用。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值