iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Java不能真正泛型的原因是什么?
  • 417
分享到

Java不能真正泛型的原因是什么?

2024-04-02 19:04:59 417人浏览 八月长安

Python 官方文档:入门教程 => 点击学习

摘要

目录简单来回顾一下类型擦除,看下面这段代码。为什么 Java 不能实现真正意义上的泛型呢?背后的原因是什么?第一,兼容性第二,不是“实现不了”总结简单来回顾一下类型擦除,看下面这段代

简单来回顾一下类型擦除,看下面这段代码。


public class Cmower {
    public static void method(ArrayList<String> list) {
        System.out.println("Arraylist<String> list");
    }
    public static void method(ArrayList<Date> list) {
        System.out.println("Arraylist<Date> list");
    }
}

在浅层的意识上,我们会认为 ArrayList<String> list 和 ArrayList<Date> list 是两种不同的类型,因为 String 和 Date 是不同的类。

但由于类型擦除的原因,以上代码是不会编译通过的——编译器会提示一个错误:

‘method(ArrayList)' clashes with ‘method(ArrayList)'; both methods have same erasure

也就是说,两个 method() 方法经过类型擦除后的方法签名是完全相同的,Java 是不允许这样做的。

也就是说,按照我们的假设:如果 Java 能够实现真正意义上的泛型,两个 method() 方法是可以同时存在的,就好像方法重载一样。


public class Cmower {
    public static void method(String list) {
    }
    public static void method(Date list) {
    }
}

为什么 Java 不能实现真正意义上的泛型呢?背后的原因是什么?

第一,兼容性

Java 在 2004 年已经积累了较为丰富的生态,如果把现有的类修改为泛型类,需要让所有的用户重新修改源代码并且编译,这就会导致 Java 1.4 之前打下的江山可能会完全覆灭。

想象一下,你的代码原来运行的好好的,就因为 jdk 的升级,导致所有的源代码都无法编译通过并且无法运行,是不是会非常痛苦?

类型擦除就完美实现了兼容性,Java 1.5 之后的类可以使用泛型,而 Java 1.4 之前没有使用泛型的类也可以保留,并且不用做任何修改就能在新版本的 Java 虚拟机上运行。

老用户不受影响,新用户可以自由地选择使用泛型,可谓一举两得。

第二,不是“实现不了”

这部分内容参考自 R大@RednaxelaFX

Pizza,1996 年的实验语言,在 Java 的基础上扩展了泛型。

Pizza 教程地址:Http://pizzacompiler.sourceforge.net/doc/tutorial.html

这里插一下 Java 的版本历史,大家好有一个时间线上的观念。

  • 1995年5月23日,Java语言诞生
  • 1996年1月,JDK1.0 诞生
  • 1997年2月18日,JDK1.1发布
  • 1998年2月,JDK1.1被下载超过2,000,000次
  • 2000年5月8日,JDK1.3发布
  • 2000年5月29日,JDK1.4发布
  • 2004年9月30日18:00 PM,J2SE1.5 发布

也就是说,Pizza 在 JDK 1.0 的版本上就实现了“真正意义上的”泛型,我引过来两段例子,大家一看就明白了。

首先是 StoreSomething,一个泛型类,标识符是大写字母 A 而不是我们熟悉的大写字母 T。


class StoreSomething<A> {
     A something;
     StoreSomething(A something) {
         this.something = something;
     }
     void set(A something) {
         this.something = something;
     }
     A get() {
         return something;
     }
}

这个 A 呢,可以是任何合法的 Java 类型:


StoreSomething<String> a = new StoreSomething("I'm a string!");
StoreSomething<int> b = new StoreSomething(17+4);
b.set(9);
int i = b.get();
String s = a.get();

对吧?这就是我们想要的“真正意义上的泛型”,A 不仅仅可以是引用类型 String,还可以是基本数据类型。要知道,Java 的泛型不允许是基本数据类型,只能是包装器类型。

除此之外,Pizza 的泛型还可以直接使用 new 关键字进行声明,并且 Pizza 编译器会从构造方法的参数上推断出具体的对象类型,究竟是 String 还是 int。要知道,Java 的泛型因为类型擦除的原因,程序员是无法知道一个 ArrayList 究竟是 ArrayList<String> 还是 ArrayList<Integer> 的。


ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<String> strs = new ArrayList<String>();
System.out.println(ints.getClass());
System.out.println(strs.getClass());

输出结果:

class java.util.ArrayList class java.util.ArrayList

都是 ArrayList 而已。

那 Pizza 这种“真正意义上的泛型”为什么没有被 Java 采纳呢?这是大家都很关心的问题。

事实上,Java 的核心开发组对 Pizza 的泛型设计非常感兴趣,并且与 Pizza 的设计者 Martin 和 Phil 取得了联系,新合作了一个项目 Generic Java,争取在 Java 中添加泛型支持,但不引入 Pizza 的其他功能,比如说函数式编程

这里再补充一点维基百科上的资料,Martin Odersky 是一名德国计算机科学家,他和其他人一起设计了 Scala 编程语言,以及 Generic Java(还有之前的 Pizza),他实现的 Generic Java 编译器成为了 Java 编译器 javac 的基础。

站在马后炮的思维来看,Pizza 的泛型设计和函数式编程非常具有历史前瞻性。然而 Java 的核心开发组在当时似乎并不想把函数式编程引入到 Java 中。

以至于 Java 在 1.4 之前仍然是不支持泛型的,为什么 Java 1.5 的时候又突然支持泛型了呢?

当然是到了不支持不行的时候了。

没有泛型之前,我们可以这样写代码:


ArrayList list = new ArrayList();
list.add("沉默王二");
list.add(new Date());

不管是 String 类型,还是 Date 类型,都可以一股脑塞进 ArrayList 当中,这看起来似乎很方便,但取的时候就悲剧了。


String s = list.get(1);

这样取行吗?

不行。

还得加上强制转换。


String s = (String) list.get(1);

但我们知道,这行代码在运行的时候必然会出错:

Exception in thread "main" java.lang.ClassCastException: java.util.Date cannot be cast to java.lang.String

这就又回到“兼容性”的问题了。

Java 语言和其他编程语言不一样,有着沉重的历史包袱,1.5 之前已经有大量的程序部署在生产环境下了,这时候如果一刀切,原来没有使用泛型的代码直接扼杀了,后果不堪想象。

Java 一直以来都强调兼容性,我认为这也是 Java 之所以能被广泛使用的主要原因之一,开发者不必担心 Java 版本升级的问题,一个在 JDK 1.4 上可以跑的代码,放在 JDK 1.5 上仍然可以跑。

这里必须得说明一点,J2SE1.5 的发布,是 Java 语言发展史上的重要里程碑,为了表示该版本的重要性,J2SE1.5 也正式更名为 Java SE 5.0,往后去就是 Java SE 6.0,Java SE 7.0。。。。

但 Java 并不支持高版本 JDK 编译生成的字节码文件在低版本的 JRE(Java 运行时环境)上跑。

针对泛型,兼容性具体表现在什么地方呢?


ArrayList<Integer> ints = new ArrayList<Integer>();
ArrayList<String> strs = new ArrayList<String>();
ArrayList list;
list = ints;
list = strs;

表现在上面这段代码必须得能够编译运行。怎么办呢?

就只能搞类型擦除了!

真所谓“表面上一套,背后玩另外一套”呀!

编译前进行泛型检测,ArrayList<Integer> 只能放 Integer,ArrayList<String> 只能放 String,取的时候就不用担心类型强转出错了。

但编译后的字节码文件里,是没有泛型的,放的都是 Object。

Java 神奇就神奇在这,表面上万物皆对象,但为了性能上的考量,又存在 int、double 这种原始类型,但原始类型又没办法和 Object 兼容,于是我们就只能写 ArrayList<Integer> 这样很占用内存空间的代码。

这恐怕也是 Java 泛型被吐槽的原因之一了。

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注编程网的更多内容!

--结束END--

本文标题: Java不能真正泛型的原因是什么?

本文链接: https://www.lsjlt.com/news/131684.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Java不能真正泛型的原因是什么?
    目录简单来回顾一下类型擦除,看下面这段代码。为什么 Java 不能实现真正意义上的泛型呢?背后的原因是什么?第一,兼容性第二,不是“实现不了”总结简单来回顾一下类型擦除,看下面这段代...
    99+
    2024-04-02
  • java为什么不能实现真正泛型
    Java 之所以不能实现真正泛型的原因有以下几点:1. Java泛型是通过类型擦除来实现的,即在编译期间将泛型类型擦除为其上界或Ob...
    99+
    2023-09-20
    java
  • 不能在PHP中使用泛型的原因是什么
    小编给大家分享一下不能在PHP中使用泛型的原因是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!为什么我们不能在 PHP 中使用泛型我们将深入探讨泛型和 PHP...
    99+
    2023-06-29
  • Java中泛型擦除的原理是什么
    这篇文章将为大家详细讲解有关Java中泛型擦除的原理是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。python是什么意思Python是一种跨平台的、具有解释性、编译性、互动性和面向对象...
    99+
    2023-06-14
  • java的ReentrantReadWriteLock不能锁升级的原因是什么
    本篇内容介绍了“java的ReentrantReadWriteLock不能锁升级的原因是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!为...
    99+
    2023-06-20
  • java泛型指的是什么
    这篇文章主要讲解了“java泛型指的是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java泛型指的是什么”吧!概念泛型是指类型可以作为参数传递,本质上是类型参数。例如,当我们定义一种方...
    99+
    2023-06-30
  • 什么情况下不能使用Java泛型
    这篇文章主要讲解了“什么情况下不能使用Java泛型”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“什么情况下不能使用Java泛型”吧!1. 前言Java 1.5 引入了泛型来保证类型...
    99+
    2023-06-02
  • java中什么是泛型
    本篇文章给大家分享的是有关java中什么是泛型,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Java的优点是什么1. 简单,只需理解基本的概念,就可以编写适合于各种情况的应用程...
    99+
    2023-06-14
  • Java泛型的特性是什么
    本篇内容介绍了“Java泛型的特性是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!泛型概述泛型在java中有很重要的地位,在面向对象编程...
    99+
    2023-06-02
  • 放弃Golang编程语言的背后真正原因是什么?
    放弃Golang编程语言的背后真正原因是什么? 作为一种高效、静态类型的编程语言,Golang(又称Go)自诞生以来备受程序员的青睐。然而,随着时间的推移,一些开发者开始放弃Golan...
    99+
    2024-03-01
    性能 兼容性 失望 标准库
  • Java泛型的作用是什么
    这篇“Java泛型的作用是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Java泛型的作用是什么”文章吧。简介泛型的作用...
    99+
    2023-06-29
  • swoole不能用sleep的原因是什么
    这篇文章主要介绍“swoole不能用sleep的原因是什么”,在日常操作中,相信很多人在swoole不能用sleep的原因是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”swoole不能用sleep的原因...
    99+
    2023-06-30
  • ChatGPT不能访问是什么原因
    ChatGPT不能访问的原因有:1、网络连接不稳定,出现chatGPTisatcapacityrightnow错误;2、网页突然打不...
    99+
    2023-02-08
    ChatGPT
  • Java泛型擦除是什么
    这篇文章主要介绍了Java泛型擦除是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Java泛型擦除是什么文章都会有所收获,下面我们一起来看看吧。泛型信息只存在于代码编译阶段,但是在java的运行期(已经生成...
    99+
    2023-06-27
  • java中的泛型指的是什么
    这篇文章主要讲解了“java中的泛型指的是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java中的泛型指的是什么”吧!目录一、什么是泛型二、语法三、示例简单示例返回最大值-支持各种数据...
    99+
    2023-06-20
  • Java中的泛型是什么意思
    这篇文章主要介绍“Java中的泛型是什么意思”,在日常操作中,相信很多人在Java中的泛型是什么意思问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Java中的泛型是什么意思”的疑惑有所帮助!接下来,请跟着小编...
    99+
    2023-06-03
  • 免费IP不能用的原因是什么
    这篇文章主要讲解了“免费IP不能用的原因是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“免费IP不能用的原因是什么”吧!1、免费代理IP可用性低。2、免费的代理IP,使用起来比较麻烦。选...
    99+
    2023-06-20
  • java线程不安全的原因是什么
    今天就跟大家聊聊有关java线程不安全的原因是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。Java可以用来干什么Java主要应用于:1. web开发;2. Android开发;...
    99+
    2023-06-14
  • Java只能单继承的原因是什么
    今天小编给大家分享一下Java只能单继承的原因是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。多继承虽然能使子类同时拥有...
    99+
    2023-07-05
  • C#中泛型的运作原理是什么
    这篇文章给大家介绍C#中泛型的运作原理是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。一.泛型之前的故事#我们肯定会想到用object来作为类型参数,因为在C#中,所有类型都是基于Object类型的。因此Objec...
    99+
    2023-06-07
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作