深入 java 的泛型之后,类型擦除搞得我很难受,毕竟向前兼容,理解。但是我看到 c#却不是用类型擦除的方式,c#也不是从一开始就有泛型的,那是不是 c#推出泛型之后,是对老代码是不兼容的?但是我记得 c#也是在很多地方都有使用的,难道 c#不考虑向前兼容吗?
ps:java 的泛型我真的吐了,java 的泛型只是代码看着好像你知道他的类型了,但其实都是 object
1
thinkershare 2022-08-24 10:09:41 +08:00 1
.NET 添加泛型的时候是在 2.0, 而且在.NET 1.0 的时候就已经考虑了泛型, 只是因为时间来不及, 所以才推迟到 2.0, 然后 C#一开始就有值类型, 为了完全的堆栈控制和性能, 如果泛型实现为擦除, 就完全残废了, Java 添加泛型的时候, Java 已经投入生产很多年了, 这个问题知乎有详细的回答, 去看看就好了.
|
2
sun1991 2022-08-24 10:10:17 +08:00
不考虑. 2.0 带来泛型后, 和 1.1 彻底割裂了.
顺便鄙视下 JAVA 的残废泛型. |
3
Chad0000 2022-08-24 10:10:50 +08:00 via iPhone
C 井 2.0 就有泛型了。C 井从来没有不兼容之前的代码。否则为啥说 C 井优雅
|
4
chendy 2022-08-24 10:17:13 +08:00
java 当初历史包袱一堆,C#后来的做的比 java 好不很正常么
|
5
cmdOptionKana 2022-08-24 10:19:30 +08:00 2
C#站在巨人(Java)的肩膀上。
|
6
guaike 2022-08-24 10:20:27 +08:00
java 的泛型就是给编译器看看的语法糖,用着是真别扭,和 C#的泛型差距不是一般的大
|
7
cheng6563 2022-08-24 10:29:29 +08:00
为了兼容性泛型擦除完全是扯淡,Java 很多地方都感觉脑子有坑才这样设计的。
|
8
Ev1s 2022-08-24 10:33:24 +08:00
现在感觉 C#有些设计真的是不错
|
10
aotuman233 2022-08-24 10:48:30 +08:00
@ghost024 java 不还是有一堆 vector 和 hashtable 这种弃用的库。。。当时要是完全添加范型然后写一套新库也不会像现在这样这么多历史包袱
|
11
camliar 2022-08-24 11:00:53 +08:00 1
可以看看 R 大之前在知乎上面的回答 https://www.zhihu.com/question/28665443/answer/118148143
|
12
WispZhan 2022-08-24 11:12:06 +08:00 1
|
14
a33291 2022-08-24 11:19:10 +08:00
C#支持泛型后,BCL 的库也提供了一套泛型实现(均在 System.Collections.Generic 命名空间下),比如 List<T>,没有泛型之前就是 ArrayList,现在这些泛型和非泛型都保留了下来能够同时使用.
向前兼容来说,1 个是不重新编译的情况下的兼容,一个是重新编译兼容.据我所知.net 应该是这 2 点都满足(注意现在有个 netcore 和 netframwork,这 2 个之间有一些割裂,具体不展开) java 了解不多,貌似即使实现为擦除好像也不是很影响?因为你在写代码的时候 IDE 和编译器保证你类型安全,至于编译后在 runtime 有什么魔法,普通人管他呢? 只从实现角度来看的话,真泛型应该还是会复杂很多. |
15
TWorldIsNButThis 2022-08-24 11:24:53 +08:00 via iPhone
c#新写了一套集合库
java 在出泛型之前已经有大量历史代码 为了实现和之前没加泛型的代码兼容所以用了擦除 |
16
aguesuka 2022-08-24 11:26:33 +08:00
Java 垃圾, 模式匹配不支持泛型就是个残疾
|
17
nothingistrue 2022-08-24 11:30:42 +08:00
.NET 到现在都经过好几次近乎重做了,经典的 .NET 4 跟 .NET 3.5 不兼容还没过去多久呢,这可不只是源代码不兼容,连运行时都不兼容。.NET 的向后兼容性,是跟 Windows 学习的,它本质上是多版本同时集成。这是要背靠 Windows Update 和微软下载中心,以及 Windows 的 dll 体系的。
Java 没有这么大的靠山,就只能单版本硬兼容。这条路,以后的.NET Core 可能也要走。 |
18
beginor 2022-08-24 12:22:14 +08:00
Java 所谓的范型就是把所有的东西都转成 Object , 而不是真正的运行时范型。
|
19
wanguorui123 2022-08-24 12:27:12 +08:00
C# 的范型比较完善可以实现很多高级功能,JAVA 的范型比较残废
|
20
voidmnwzp 2022-08-24 12:44:07 +08:00 via iPhone
Java 的假闭包 直接 copy 变量值类型 而非指针 导致强行限制只能用 nt 一样的 final 变量
假泛型 倒是乏善可陈 勉强能用 |
21
dcsuibian 2022-08-24 13:13:33 +08:00
感觉还好,虽然是伪泛型,但用起来也没特别不方便
特别是学了 TypeScript 以后 |
22
FYFX 2022-08-24 13:30:06 +08:00
所以 Java 的类型擦除给你带来了哪些麻烦呢?目前来看最大的问题还是不支持值类型会影响性能,不过 Valhalla 就是在填这个坑
|
23
a33291 2022-08-24 13:35:48 +08:00
@FYFX 个人看法是伪泛型实现也意味着运行时基础设施的不完善,从而无法支持一些高级特性.其中比较明显的不足就是比如各种 ORM 的实现上,C#使用表达式树和泛型配合可以实现比如 ef 或 linq to sql 这类 orm,java 的 orm 相比之下由于这些限制,存在语法表达上的不自然.至于代码对比我就不写了,太多了.
|
24
ipwx 2022-08-24 13:42:56 +08:00
我来歪个楼。
Go:大道至简,泛型是邪道。 |
25
someonedeng 2022-08-24 14:59:42 +08:00
@ipwx go1.18 怎么说?
|
26
ghost024 OP @FYFX 写泛型代码时,我不知道运行时类型,如果我想在运行时知道具体类型的时候,我是需要先在泛型类中先给一个 class<T>的类型字段来进行补偿性的恢复类型的,我觉得这让我很困惑,我在代码层面看似已经知道了类型,但其实一无所知,甚至我要创建 T[]的数组都需要 Array.newInstance()来进行创建,这种好像知道了但是其实啥都不知道,感觉很割裂
|
27
cnbatch 2022-08-24 16:46:36 +08:00
要不试试打开编译选项 -parameters
|
28
nothingistrue 2022-08-24 17:27:33 +08:00
@ghost024 #26 Java 泛型只存在编译时,运行时除了一些特殊的黑科技,是没有泛型的,所以不要往这方面想。Java 泛型脱胎于 C++ 的模板,那货也是只存在编译时不存在运行时的,这个底层架构决定了除非重新设计否则是无法提高的。至于为什么不重新设计呢,大概是因为在非数据集合的场景,注解比泛型更好用。
|
29
Cbdy 2022-08-24 17:44:01 +08:00 via Android
比起 C#的泛型,我更喜欢 Java 、TypeScript 的编译时泛型
|
30
ghost024 OP @nothingistrue java 确实是和 c++的模版方法很像,java 和 c++还不一样,比如一个类 A ,里面有一个方法 b ,如果是 c++的泛型,我可以直接在泛型里面这样写 t.b(),他能够在编译时就知道传入的这个泛型的这个类里有这个方法,但是 java 是需要加上 T extends A 才能这样写…..
|
31
hhyyd 2022-08-24 21:11:04 +08:00
今天正好看到一张表情包:
一个妈妈,和两个孩子 java 和 c# 妈妈:喊 java 你过来干嘛干嘛 c#: 妈妈你怎么从来不喊我的名字 妈妈: 好的,microsoft java ...... 我 ??? |
32
hez2010 2022-08-24 21:54:16 +08:00 1
@nothingistrue @ghost024
Java 的泛型根本就不是脱胎于 C++ 的模板。 C++ 的模板会在编译时将泛型参数进行特化,为每一个类型的泛型参数生成单独的代码; C# 则是运行的时候进行特化,为每一个值类型生成单独的代码,而引用类型采用共享代码但是运行时分发来进行特化;而 Java 直接全部擦除成没有泛型的类,也就是说 `List<Integer>`、`List<Object>` 和 `List` 之间没有区别。 放一个静态成员 `M` 进去,在 C++ 和 C# 里,`List<Integer>.M`、`List<Object>.M` 和 `List.M` 都是独立的实例,而在 Java 中全都是同一个实例。 因此这也就决定了 Java 完全不具备参数化多态的能力,而 C++ 和 C# 都具备这个能力,于是在这个范式上构建的一切语言特性 Java 都无法实现。 |
33
mmdsun 2022-08-24 22:21:05 +08:00
吐槽 Java 泛型:
1 、new Array<int>(); //不合法要用 Integer ,不支持值类型。 2 、if(obj instanceof T) //不合法,不支持泛型 3 、E ele = new E() //不合法,不支持泛型对象、数组,创建。 4 、 void method(List<String> p); void method(List<Integer> p); //不合法,泛型擦除后不支持重载 最后,Java 泛型擦除是方法的 CODE 属性字节码,实际上在元数据中还是保留了泛型信息,在反射时也能获取泛型类型,只是需要一点“小技巧”。 [上面代码也能用特殊的方式实现] C#是站在 Java 肩上设计开发。 不过 C#很多特性确实十分优秀而且语法类似 Java ,C sharp 也是 Java 开发者推荐学习的第二语言之一,估计可以半天入门。 |
34
ghost024 OP @hez2010 只能说 java 的泛型也是借鉴了 c++的模版,但里面并不完全一样(我的 c++只学了皮毛中的皮毛,多谢老哥解释)
|
35
ghost024 OP @mmdsun 第二种情况可以在里面存一个 class<T>的字段就可以这样比较了,如果不恢复类型的话,单纯的比较确实不行
|
36
FrankHB 2022-08-24 23:09:40 +08:00
@cheng6563 很多设计是因为脑子有坑是对的,但说句公道话,Java 泛型哪来的脑子有坑的设计,在就是根本没设计,搞得后来不适合用不坑的方式扩展了。( C++模板也是在完全没管参数多态的 C 上加的。)
核心标志就是 JVM 不支持泛型的类型元数据。这导致要么实现成 C++那种翻译时展开,要么类型擦除,都可以实现不依赖运行时元数据。 @camliar 兼容性方面说得有问题。 如果选用编译时展开,仍然可以二进制兼容,类似 C++多了 name mangling 以后原则上也能支持 C ABI ,无非是要多出来 linkage convention 。相比 C++考虑互操作问题要求用户手动 extern "C"区分,这个在 Java 里可以隐式自动解决,毕竟 JVM 在 spec 层次上完全控制 loader 的细节,多加 phase 重新生成代码也不在话下。 只是这样毫无疑问地会更复杂,而在 Java 的维护者的潜意识中不太值罢了。 @nothingistrue 工程上来讲.NET 那套更符合实际需求。 这不是靠山大不大的问题,而是如果没觉悟搞定多版本共存,二进制分发代码迟早变成 DLL hell 还可能到处依赖错误的屎山,要么就是用户自己实现备胎。这历史上已经重演了很多遍了。CLR 其实也不厚道,GAC 自己还是分版本的 hell ,如果把这方面控制权给用户(系统管理员)可能还不会那么烂。 @dcsuibian TypedScript 作为动态语言情况有点不大一样。 原则上 ES 实现的 IR 不需要公开,TS 实现除了编译器,也可以多加辅助运行时实现类似 CLR 的元数据,甚至干脆 TS 自己一个库就实现了。所以就算一时比较坑,也不碍着以后再慢慢加上改进特性,而可以做到避免有明显的兼容性问题。( ES/TS 自己具体特性设计拉胯不够容易实现出来这样的运行时,非得依赖 ES 的运行时开洞,那就另说了。) Java 不一样,JVM bytecode 就是 bytecode ,和 Java 源码是两回事。Java 作为静态语言就没这种扩展取代 bytecode 地位的余地,想要改掉就要差不多 Java 到 JVM 整个设计竖着砍一刀挖掉重新填埋。 @someonedeng Go 是想学 CLR 这样在 C++和 Java 中间划清界限避免缺陷,结果画虎类犬: www.infoq.cn/article/xprmcl5qbf6yvdroajyn |
37
Nerv 2022-08-24 23:44:28 +08:00
不能存基本类型的泛型,冗长的语法,java 真的屑。
|
38
wetalk 2022-08-25 10:48:03 +08:00
呐,这就是 C#打不过 Java 的原因
|
39
allgy 2022-08-25 11:12:15 +08:00
C#适合程序员(写起来优雅,早下班),JAVA 适合老板(卷,压工价,好找人)
|
40
forgottencoast 2023-09-22 23:32:28 +08:00
|