Java 泛型小结

目录

泛型的定义

泛型分类

限定泛型类型变量

泛型的意义

泛型的原理

泛型中的约束和局限性

泛型的定义

泛型,即“参数化类型”。就是将程序需要的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。

一些常用的泛型类型变量:
E:元素(Element),多用于java集合框架
K:关键字(Key)
N:数字(Number)
T:类型(Type)
V:值(Value)

泛型分类

泛型分为“泛型类”、“泛型接口”和“泛型方法”。

泛型类:

public class GenericClass<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

泛型接口:

public interface GenericIntercace<T> {
     T getData();
}

泛型方法:

    private static <T> T genericAdd(T a, T b) {
        System.out.println(a + "+" + b + "="+a+b);
        return a;
    }

限定泛型类型变量

Java中的限定通配符包括:

  • <? extends Parent> 指定了泛型类型的上界,即传入的类型必须是Parent的子类或实现类。
  • <? super Child> 指定了泛型类型的下界,即传入的类型必须是Child的父类。
  • <?>或<T等符号>  表示没有限制的泛型类型。

如:public class Test<T extends Number> {},public <T super Integer> T add(T num1 ,T num2){}。

泛型的意义

  1. 能够复用代码。
  2. 编译期间类型检查,避免类型转换异常。

复用代码。我们以List集合举例,若我们要自己实现一个List集合,那么可能首先想到的是创建多个List类,这样我们为了做到可以在List中放入任何类型的数据,我们必须定义相同数量的List类,如:

class List1{
    Integer[] data;
    void add(Integer p);
    Integer get(int index);
}

class List2{
    Float[] data;
    void add(Float p);
    Float get(int index);
}

......

类型安全。在上面的基础上,有一种方法可以避免大量重复代码,那就是Object[] data。这样我们可以传入任何对象,但另一个问题来了,存数据的时候很nice,但是取数据的时候返回的也是Object对象,这样我们就必须进行类型强转,这样很有可能出现类型转化异常。

class List{
    Object[] data;
    void add(Object p);
    Object get(int index);
}

List list = new List();
list.add(10);
list.add("hello");
Integer v1 = (Integer)list.get(0);
Stringv1 = (String)list.get(1);

显然,使用泛型,就很好的避免了上面两个问题:

List<String> list = new ArrayList<>();
list.add("hello");
String value = list.get(0);

List<Integer> list = new ArrayList<>();
list.add(1);
Integervalue = list.get(0);

泛型的原理

Java语言中的泛型只在源码中存在,在编译后的字节码文件中,就已经替换为原来的原生类型了,并且在相应的地方插入了强制转型代码(被称作“泛型擦除”)。因此,对于运行期的Java语言来说,ArrayList<Integer>与ArrayList<String>就是同一个类。需要注意的是,Java中泛型在运行期是不可见的,会被擦除为它的上级类型。如果是没有限定的泛型参数类型,就会被替换为Object。

下面是一个Java泛型的例子,是泛型擦除前的代码:

    public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();
        map.put("hello","你好");
        map.put("how are you?","吃了没?");
        System.out.println(map.get("hello"));
        System.out.println(map.get("how are you?"));
    }

将上面代码编译成Class文件,然后再用字节码反编译工具进行反编译后,将会发现泛型都不见了,程序又变回了Java泛型出现之前的写法,泛型类型都变回了原生类型,如下:

    public static void main(String[] args) {
        Map<Object,Object> map = new HashMap<>();
        map.put("hello","你好");
        map.put("how are you?","吃了没?");
        System.out.println((String)map.get("hello"));
        System.out.println((String)map.get("how are you?"));
    }

泛型中的约束和局限性

  • 不能实例化泛型类
  • 静态变量或方法不能引用泛型类型变量,但是静态泛型方法是可以的
  • 基本类型无法作为泛型类型
  • 无法使用instanceof关键字或==判断泛型类的类型
  • 泛型类的原生类型与所传递的泛型无关,无论传递什么类型,原生类是一样的
  • 泛型数组可以声明但无法实例化
  • 泛型类不能继承Exception或者Throwable
  • 不能捕获泛型类型限定的异常但可以将泛型限定的异常抛出

参考:https://www.jianshu.com/p/986f732ed2f1,《深入理解Java虚拟机》,https://www.cnblogs.com/huansky/p/8043149.html

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值