Java泛型漫谈

介绍java泛型的定义以及实际的具体使用方法。

什么是泛型?

泛型是JDK5引入的新特性,本质是参数化类型。在定义的时候无需知道参数的具体类型,即将参数类型推迟到使用时决定。

这种参数类型可以体现在类,接口,方法中,我们可以称呼为泛型类,泛型接口,泛型方法。

为什么使用泛型?

  • 保证类型安全

    举个例子,我们都知道List只能存放同种类型的参数,在没有泛型之前是无法得知不同类型的参数存放到同一个list中是否报错

    /**
    * 泛型出现之前
    */
    List list = new ArrayList();
    // 本意是想在该list中存放字符串类型的参数
    list.add("测试");
    // 由于没有泛型指定参数类型,同样编译通过
    list.add(1);
    
    /**
    * 泛型出现之后
    */
    List<String> list = new ArrayList<>();
    // 本意是想在该list中存放字符串类型的参数
    list.add("测试");
    // 编译失败
    list.add(1);
    
  • 消除强制转换

    如果没有泛型,无法得知List中存放的具体是某种参数类型,所以无法避免强制转换。

    /**
    * 泛型出现之前
    */
    List list = new ArrayList();
    // 本意是想在该list中存放字符串类型的参数
    list.add("测试");
    // 必须通过强制转换
    String a = (String) list.get(0);
    
    /**
    * 泛型出现之后
    */
    List<String> list = new ArrayList<>();
    // 本意是想在该list中存放字符串类型的参数
    list.add("测试");
    // 无需强制转换
    String a = list.get(0);
    
  • 避免重复拆装箱操作

  • 提高代码可用性

泛型使用

泛型命名规范,一般都是使用单个大写字母来指定,例如T或者R等等。

泛型类

泛型定义在类上,定义格式如下:

public class ClassName <T> {
    
}

我们模拟一个场景,小朋友写数字,有些小朋友写的int类型的阿拉伯数字,有些小朋友写的是字符串的中文数字,于是我们定义一个Child类,并指定一个泛型T来接收小朋友报的数:

public class Child <T> {
    private T value;
    
    // 定义一个泛型T构造函数
    public Child(T value) {
        this.value = value;
    }
 
    public T getValue() {
        return value;
    }
 
    public void setValue(T value) {
        this.value = value;
    }

}
public static void main(String[] args){
    Child<String> childOne = new Child<>("一");
    // 1号小朋友写的是字符串类型的中文数字一
    System.out.println(childOne.getValue());
    Child<Integer> childTwo = new Child<>(1);
    // 2号小朋友写的是字符串的int类型的阿拉伯数字1
    System.out.println(childTwo.getValue());
}

泛型接口

泛型定义在接口中,例如:

public interface Test<T>{
    void test(T value);
}

泛型方法

泛型定义在方法上,定义格式如下:

public <T> T test(T t){
    return t;
}

举例,接收同种类型的两个参数,输出不为null的结果:

public static <T> T firstNonNull(@CheckForNull T first, T second) {
    if (first != null) {
        return first;
    }
    if (second != null) {
        return second;
    }
    throw new NullPointerException("Both parameters are null");
}

该例子取自Google的guava源码。

扩展

对于泛型经常使用的还有泛型通配符,有以下三种使用方式:

  1. <?>无边界的泛型
  2. <? extends E>上边界泛型
  3. <? super E>下边界泛型
public class MyClass <?>{
}

public class MyClass <T extends XxxClass>{
}

public class MyClass <T super XxxClass>{
}

源码中的泛型通常使用E,K,V等,实际上他们都是有实际含义的:

E:Element (在集合中使用,因为集合中存放的是元素)
T:Type(Java 类)
K:Key(键)
V:Value(值)
N:Number(数值类型)
?:表示不确定的java类型

那么我们再思考一个问题,泛型具体是如何实现的呢。

我们都知道Object是所有类的父类,那么实际上泛型就是当你定义的时候用Object来接收,然后通过尖括号里定义的泛型类型来进行类型限定,例如String或者Integer等

除非是使用了泛型通配符,例如,那么会使用Aclass来接收。

参考资料:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值