c#和 Java 感觉好像,但是对泛型还是有疑问

2022-08-24 10:05:42 +08:00
 ghost024

深入 java 的泛型之后,类型擦除搞得我很难受,毕竟向前兼容,理解。但是我看到 c#却不是用类型擦除的方式,c#也不是从一开始就有泛型的,那是不是 c#推出泛型之后,是对老代码是不兼容的?但是我记得 c#也是在很多地方都有使用的,难道 c#不考虑向前兼容吗?

ps:java 的泛型我真的吐了,java 的泛型只是代码看着好像你知道他的类型了,但其实都是 object

4521 次点击
所在节点    程序员
40 条回复
dcsuibian
2022-08-24 13:13:33 +08:00
感觉还好,虽然是伪泛型,但用起来也没特别不方便

特别是学了 TypeScript 以后
FYFX
2022-08-24 13:30:06 +08:00
所以 Java 的类型擦除给你带来了哪些麻烦呢?目前来看最大的问题还是不支持值类型会影响性能,不过 Valhalla 就是在填这个坑
a33291
2022-08-24 13:35:48 +08:00
@FYFX 个人看法是伪泛型实现也意味着运行时基础设施的不完善,从而无法支持一些高级特性.其中比较明显的不足就是比如各种 ORM 的实现上,C#使用表达式树和泛型配合可以实现比如 ef 或 linq to sql 这类 orm,java 的 orm 相比之下由于这些限制,存在语法表达上的不自然.至于代码对比我就不写了,太多了.
ipwx
2022-08-24 13:42:56 +08:00
我来歪个楼。

Go:大道至简,泛型是邪道。
someonedeng
2022-08-24 14:59:42 +08:00
@ipwx go1.18 怎么说?
ghost024
2022-08-24 16:13:23 +08:00
@FYFX 写泛型代码时,我不知道运行时类型,如果我想在运行时知道具体类型的时候,我是需要先在泛型类中先给一个 class<T>的类型字段来进行补偿性的恢复类型的,我觉得这让我很困惑,我在代码层面看似已经知道了类型,但其实一无所知,甚至我要创建 T[]的数组都需要 Array.newInstance()来进行创建,这种好像知道了但是其实啥都不知道,感觉很割裂
cnbatch
2022-08-24 16:46:36 +08:00
要不试试打开编译选项 -parameters
nothingistrue
2022-08-24 17:27:33 +08:00
@ghost024 #26 Java 泛型只存在编译时,运行时除了一些特殊的黑科技,是没有泛型的,所以不要往这方面想。Java 泛型脱胎于 C++ 的模板,那货也是只存在编译时不存在运行时的,这个底层架构决定了除非重新设计否则是无法提高的。至于为什么不重新设计呢,大概是因为在非数据集合的场景,注解比泛型更好用。
Cbdy
2022-08-24 17:44:01 +08:00
比起 C#的泛型,我更喜欢 Java 、TypeScript 的编译时泛型
ghost024
2022-08-24 18:20:41 +08:00
@nothingistrue java 确实是和 c++的模版方法很像,java 和 c++还不一样,比如一个类 A ,里面有一个方法 b ,如果是 c++的泛型,我可以直接在泛型里面这样写 t.b(),他能够在编译时就知道传入的这个泛型的这个类里有这个方法,但是 java 是需要加上 T extends A 才能这样写…..
hhyyd
2022-08-24 21:11:04 +08:00
今天正好看到一张表情包:

一个妈妈,和两个孩子 java 和 c#

妈妈:喊 java 你过来干嘛干嘛

c#: 妈妈你怎么从来不喊我的名字

妈妈: 好的,microsoft java

...... 我 ???
hez2010
2022-08-24 21:54:16 +08:00
@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 都无法实现。
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 开发者推荐学习的第二语言之一,估计可以半天入门。
ghost024
2022-08-24 22:53:25 +08:00
@hez2010 只能说 java 的泛型也是借鉴了 c++的模版,但里面并不完全一样(我的 c++只学了皮毛中的皮毛,多谢老哥解释)
ghost024
2022-08-24 22:55:40 +08:00
@mmdsun 第二种情况可以在里面存一个 class<T>的字段就可以这样比较了,如果不恢复类型的话,单纯的比较确实不行
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
Nerv
2022-08-24 23:44:28 +08:00
不能存基本类型的泛型,冗长的语法,java 真的屑。
wetalk
2022-08-25 10:48:03 +08:00
呐,这就是 C#打不过 Java 的原因
allgy
2022-08-25 11:12:15 +08:00
C#适合程序员(写起来优雅,早下班),JAVA 适合老板(卷,压工价,好找人)
forgottencoast
2023-09-22 23:32:28 +08:00
@nothingistrue
“经典的 .NET 4 跟 .NET 3.5 不兼容还没过去多久呢”
这个详细说说?哪些部分是不兼容的?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/874974

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX