首页后端开发JAVAJava泛型中的异同分析

Java泛型中的异同分析

时间2023-04-25 01:57:01发布访客分类JAVA浏览575
导读:点击上方蓝色“程序猿DD”,选择“设为星标”回复“资源”获取独家整理的学习资料!作者 | 刘一手 来源 | 公众号「锅外的大佬」Java Generics – <?> vs <? extends Object>相信很...

点击上方蓝色“程序猿DD”,选择“设为星标”

回复“资源”获取独家整理的学习资料!

作者 | 刘一手

来源 | 公众号「锅外的大佬」

Java Generics – ?> vs ? extends Object>

相信很多人和我一样,接触Java多年,却仍旧搞不清楚 Java 泛型中 ?> 和 ? extends Object> 的相似和不同。但是,这应该是一个比较高端大气上档次的Question, 在我们进行深入的探讨之前,有必要对Java泛型有一个基础的了解。如果还不了解的,请看上一篇文章!

上一篇文章地址:(http://mp.weixin.qq.com/s?__biz=MzIzNzYxNDYzNw==& mid=2247484950& idx=1& sn=688f958d6f343ee2e314a724ee1129a3& chksm=e8c4a554dfb32c421bb1ac3e0fd461d997d82b68ffc8ea41367a71d537df4a7455af5810e3f4& scene=21#wechat_redirect)

1. 泛型产生的背景

在 JDK5 中引入了泛型来消除编译时错误和加强类型安全性。这种额外的类型安全性消除了某些用例中的强制转换,并使程序员能够编写泛型算法,这两种方法都可以生成更具可读性的代码。

例如,在 JDK5 之前,我们必须使用强制转换来处理列表的元素。这反过来又产生了一类特定的运行时错误:

List aList = new ArrayList();
    
aList.add(new Integer(1));
    
aList.add("a_string");
    
        
for (int i = 0;
     i  aList.size();
 i++) {
    
    Integer x = (Integer) aList.get(i);

}
    

现在,我们想解决两个问题:

  • 我们需要一个显式转换来从 aList 中提取值——类型取决于左侧的变量类型(在本例中为Integer
  • 当我们试图将 a_string 转换为 Integer 时,在第二次迭代中会出现运行时错误。

泛型填补了这个空白,代码如下:

ListInteger>
     iList = new ArrayList>
    ();
    
iList.add(1);
    
iList.add("a_string");
     // compile time error
 
for (int i = 0;
     i  iList.size();
 i++) {
    
    int x = iList.get(i);

}
    

执行上述代码,编译器会告诉我们,无法将 a_string 添加到 Integer 类型的 List 中,这比起在运行时才发现异常要好很多。而且,不需要显式转换,因为编译器已经知道 iList 包含 Integer类型的数据。另外,由于自动拆箱的关系,我们甚至不需要使用 Integer 类型,它的原始类型就足够了。

2. 泛型中的通配符

问号或通配符在泛型中用来表示未知类型。它可以有三种形式:

  • 无界通配符:List?> 表示未知类型的列表
  • 上界通配符:List? extends Number> 表示 Number 或其子类型(如IntegerDouble)的列表
  • 下界通配符:List? super Integer> 表示Integer或其超类型NumberObject的列表

由于 Object 是 Java 中所有类型的固有超类,所以我们会认为它也可以表示未知类型。换句话说,List?>  和ListObject>  可以达到相同的目的。但事实并非如此。

来看看这两个方法:

public static void printListObject(ListObject>
 list) {
    
    for (Object element : list) {
            
        System.out.print(element + " ");
    
    }
        
}
        
 
public static void printListWildCard(List?>
 list) {
    
    for (Object element: list) {
            
        System.out.print(element + " ");
    
    }
     
}
    

给出一个整数的列表,比如:

ListInteger>
     li = Arrays.asList(1, 2, 3);
    

执行 printListObject(li) 不会编译,并且我们将得到以下错误:

The method printListObject(ListObject>
    ) is not applicable for the arguments (ListInteger>
    )

而执行 printListWildCard(li) 将通过编译,并将 1 2 3 输出到控制台。

3. ?> 和? extends Object> 的相同之处

在上面的示例中,如果我们将 printListWildCard 方法更改为:

public static void printListWildCard(List? extends Object>
     list)

它的工作方式与 printListWildCard(List?> )相同。这是因为 Object 是 Java 所有对象的超类,基本上所有的东西都扩展了Object。因此,这个方法也会处理一个 Integer 类型的List。

也就是说, ?> 和 ? extends Object> 在这个例子中是同一个意思。

虽然在大多数情况下,这是正确的,但也有一些区别。接下来我们就来看看它们之间的差异。

4. ?> 和? extends Object> 的不同之处

可重构类型是指那些在编译时未被擦除的类型。换句话说,一个不可重构类型,运行时将比编译时表达的信息更少,因为其中一些信息会被擦除。

一般来说,参数化类型是不可重新定义的。比如 ListString>  和 MapInteger,String>  就不可重新定义。编译器会擦除它们的类型,并将它们分别视为列表和映射。

这个准则的唯一例外是无界通配符类型。也就是说, List?>  以及 Map?, ?>  是可重写的。

另外,List? extends Object>  不可重写。虽然微妙,但这是一个显著的区别。

不可重构的类型在某些情况下不能使用,例如在 instanceof 运算符或作为数组的元素。

所以,如果我们的代码写成这样:

List someList = new ArrayList>
    ();
    
boolean instanceTest = someList instanceof List?>
    

代码编译后,instanceTest 为true。但是,如果我们在 List? extends Object>  上使用 instanceof 运算符:

List anotherList = new ArrayList>
    ();
    
boolean instanceTest = anotherList instanceof List? extends Object>
    ;
    

那么第2行不编译。类似地,在下面的代码片段中,第1行编译,但第2行不编译:

List?>
    [] arrayOfList = new List?>
    [1];
    
List? extends Object>
    [] arrayOfAnotherList = new List? extends Object>
    [1]

好了,文章到此就划上句号了,在本文中,我们主要讨论了?> 和 ? extends Object> 的异同,虽然基本上是相似的,但两者在可变与否方面存在细微差异。

DD自研的沪牌代拍业务,点击直达

【往期推荐】

索赔 100 万!只是因为一个开源插件?

2020-11-21

快速搞懂监控、链路追踪、日志三者的区别

2020-11-21

读完《Effective Java》后,总结了 50 条开发技巧

2020-11-20

35岁之后,你还会继续写代码吗?

2020-11-19

11月全国招程序员34万人,猜猜平均工资是多少?

2020-11-18

扫一扫,关注我

一起学习,一起进步

每周赠书,福利不断

深度内容

推荐加入

声明:本文内容由网友自发贡献,本站不承担相应法律责任。对本内容有异议或投诉,请联系2913721942#qq.com核实处理,我们将尽快回复您,谢谢合作!

javaobject编译泛型重构

若转载请注明出处: Java泛型中的异同分析
本文地址: https://pptw.com/jishu/7848.html
不敢相信,居然用Java写了个“天天酷跑”! 虎牙二面:说说你对 Java “零拷贝”的理解?

游客 回复需填写必要信息