Java 的泛型能够向 golang 一样, T 可以表示多个类型? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
jeesk
V2EX    程序员

Java 的泛型能够向 golang 一样, T 可以表示多个类型?

  jeesk 2022-12-25 00:49:47 +08:00 5131 次点击
这是一个创建于 1042 天前的主题,其中的信息可能已经有所发展或是发生改变。
func SumIntsOrFloats[K comparable, V int | float64](m map[K]V) V { var s V for _, v := range m { s += v } return s } 

比如上面这段代码? v 表示的是两种类型。 但是 java/kotlin 里面好像只有上限和下限。

 fun <T : File> getString(uri: T): T { return uri } 

kotlin 里面的 T ,类型只有一种,感觉是真的不方便? 各位大神,kotlin 或者 java 有没有其他的写法支持多种类型?

30 条回复    2022-12-27 08:38:50 +08:00
Rocketer
    1
Rocketer  
   2022-12-25 01:07:46 +08:00 via iPhone
只有弱类型语言才可能这样,比如 TypeScript 也可以。

强类型语言的优势就是强类型,不方便只是你不习惯,并不是弱点。
jeesk
    2
jeesk  
OP
   2022-12-25 01:08:55 +08:00
@Rocketer golang 是个例外?
Trim21
    3
Trim21  
   2022-12-25 01:34:38 +08:00
@jeesk #2

golang 的泛型也不一定能表示多个类型,你的例子是基础类型,用到的也只是 + ,所以可以这样写。

但如果换成 struct 的话就不行了


type T1 struct {
}

func (t T1) Close() error {
return nil
}

type T2 struct {
}

func (t T2) Close() error {
return nil
}

这个可以编译

var _ io.Closer = T1{}
var _ io.Closer = T2{}


但这个泛型函数没法编译

func CanNotCompile[T T1 | T2](t T) error {
return t.Close()
}
TWorldIsNButThis
    4
TWorldIsNButThis  
   2022-12-25 01:34:49 +08:00
overload
GeruzoniAnsasu
    5
GeruzoniAnsasu  
   2022-12-25 02:37:15 +08:00
@Trim21 可以绕:

type typeProxy interface {
Close() error
}

func CanCompile[T T1 | T2](t T) error {
return any(t).(typeProxy).Close()
}

CanCompile(T3{}) // 拒绝编译


--------

java 的泛型系统的「类型限制」( constraint )只能指定类型继承链上的上下界,泛型容器或泛型方法仅仅是把对象的类型自动向上转换而已,因此不可能指定不在同一继承链上的两个任意类型的组合类型( T | U ),设想 (T|U) t; t.Method(); 此时 t 的类型只能协变为 Object ,而 Object 不会有 Method()方法。

这跟强弱类型语言没什么关系,跟泛型系统的实现和设计有关,只能说,java 就这样,你想实现接近的效果,有非泛型的写法( instanceof )
Leviathann
    6
Leviathann  
   2022-12-25 02:54:26 +08:00
java 没有或类型,要表达同一个意思,就是用重载
pennai
    7
pennai  
   2022-12-25 04:09:42 +08:00
c++可以
kakach
    8
kakach  
   2022-12-25 06:50:06 +08:00 via Android   1
BBCCBB
    9
BBCCBB  
   2022-12-25 09:27:38 +08:00
interface/abstract, 比如(Number t), t 可以传 int, float, double, long 等, 不过必须子类实现父类才行,,
不能像 go 这样直接指定多个.
jeesk
    10
jeesk  
OP
   2022-12-25 09:30:07 +08:00 via Android
@GeruzoniAnsasu 所以 java 的泛型是假的, 语法糖
looplj
    11
looplj  
   2022-12-25 09:35:01 +08:00   3
不是一句假的这么简单。。

泛型有很多种实现方式,CPP 的基于模板的,Go 也类似基于模板的,Java 是基于类型擦除的,各有优劣。

而且,不支持 union type ,只是语言层的问题,和泛型实现没什么关系,有需要的话,Java 也可以支持。
coala
    12
coala  
   2022-12-25 10:52:51 +08:00
Java 的泛型是假的. class 文件反编译后你就看到了,new ArrayList<String>() 反编译后是 new ArrayList(), 其他语言的是怎么实现的不清楚, 但是 Java 算是比较取巧的方式吧, 大概只有编译时检查泛型, 实际上最下面还是 object
iseki
    13
iseki  
   2022-12-25 10:54:04 +08:00 via Android
不支持联合类型,和泛型其实没太大关系,你看 ts 不用泛型也能联合类型。语言设计问题,可能和 Java 是名义类型有点关系,也许联合类型这种情况下不太好实现?
iseki
    14
iseki  
   2022-12-25 10:57:07 +08:00 via Android
至于类型擦除…Java 这种实现的好处是代码不膨胀,和旧的兼容,运行时也没额外消耗,坏处就是运行时不一定能拿到泛型信息
coala
    15
coala  
   2022-12-25 11:01:28 +08:00
感觉这就和茴的几种写法一样.. 泛型是为了什么呢, 如果是为了统一类型, 一个 ArrayList 你说允许有两种类型. 我这写了几年 Java 的脑回路反而有点不适, 无法就是在灵活和规整直接做取舍
jeesk
    16
jeesk  
OP
   2022-12-25 11:04:46 +08:00 via Android
@coala 少写代码。 比如别人的接口参数就是 object 类型, 支持的就是 string 或者 int 类型,我要限制类型, 这个时候我要写 2 个方法分别是 stringh 和 int 的类型, 少写点代码就少写。
jeesk
    17
jeesk  
OP
   2022-12-25 11:06:34 +08:00 via Android
@coala 你写写其它语言就知道了,java 太不灵活了, 对于个人项目重构成本高。
iseki
    18
iseki  
   2022-12-25 11:07:46 +08:00 via Android
@jeesk 我觉得你举的这个例子用 union type 不太好,overload 更合适。你写了个 string | int ,里面还是要 is string is int 分别去处理
jeesk
    19
jeesk  
OP
   2022-12-25 11:09:16 +08:00 via Android
@iseki 不用处理啦。别人的接口就是 object 类型。
iseki
    20
iseki  
   2022-12-25 11:10:15 +08:00 via Android
噢,我懂了,你是额外在人家的接口上加了个约束
jeesk
    21
jeesk  
OP
   2022-12-25 11:10:50 +08:00 via Android
@iseki 重载也行, 不过能像 golang 一样能省就好了。
coala
    22
coala  
   2022-12-25 11:49:45 +08:00
@jeesk 第一次写 node.js 的时候, 当时实现了一个简单 WebSocket Server, node.js 居然只用 1 个文件 20 多行代码就搞定了, Java 干这个事得定义了好几个对象, 几个文件配合干, 代码很容易一大片。 对我来说非常震撼。

Java 现在只在编译时检查一个泛型, 看上去实现检查 2 个泛型也不是什么难事, 兼容旧版这种理由我是不信的, 编译时能检查一个也能检查两个 , 反正是 "假泛型"。 我更倾向于作者就是觉得只允许一个类型更好一点。 像 Python 强制 4 个空格的语法, 咱也不敢骂。

没有泛型好, 还是只有一种类型好, 还是支持多种类型好, 真的有答案吗?
jeesk
    23
jeesk  
OP
   2022-12-25 12:03:46 +08:00
@coala java 也能呀, 都写在一个文件里面不是问题。
coala
    24
coala  
   2022-12-25 12:19:49 +08:00
@iseki 是的, 我也觉得 Golang 更好一点, Java 一般
iseki
    25
iseki  
   2022-12-25 12:24:38 +08:00
@coala 不不不,我觉得 Go 是一个设计的很差的语言,Java 太罗嗦,我选择 Kotlin (洗手)
coala
    26
coala  
   2022-12-25 12:36:18 +08:00
@iseki 2333, 圈错了, Sorry...
Huelse
    27
Huelse  
   2022-12-25 13:51:41 +08:00
可能 Scala3 更符合你的需求,如 Intersection Types, Union Types 等等 https://dotty.epfl.ch/
lisongeee
    28
lisongeee  
   2022-12-25 13:55:58 +08:00
kotlin 可以通过密封类实现联合类型类似效果,但是不如 typescript 灵活
hhjswf
    29
hhjswf  
   2022-12-26 14:38:29 +08:00
@coala 你不会是手撸的吧? Java 用现成的轮子基于注解还是可以的
netabare
    30
netabare  
   2022-12-27 08:38:50 +08:00 via Android   1
这个是 sum type ,typescript 里面有不错的支持。kotlin 和 java 都没有,得用 scala ,不然就是纯 fp 的 ocaml 、haskell 之类的语言才有了。

sealed class 模拟的问题在于不能用再已有的类型上,必须手写一层例如 IntWrapper 、StringWrapper 之类的层来套着,对数据互转很不方便。
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2173 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 27ms UTC 00:44 PVG 08:44 LAX 17:44 JFK 20:44
Do have faith in what you're doing.
ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86