Java方法错误地自动在kotlin中重载

给定一个包含以下(精简)类的Java库:

public class Vector2f { public float x; public float y; public Vector2f div(Vector2f other) { x /= other.x; y /= other.y; return this; } public Vector2f div(Vector2f other, Vector2f dest) { dest.x = x / other.x; dest.y = y / other.y; return dest; } /* ... */ } 

由于kotlin自动将合适的方法名称转换为重载操作符,我可以写

 val v0 = Vector2f(12f, 12f) val v1 = Vector2f(2f, 2f) val res = v0 / v1 println(v0) println(v1) println(res) res.x = 44f println() println(v0) println(v1) println(res) 

…意外的结果是v0被中缀除法操作所突变。 此外, res存储的引用指向与v0相同的对象。输出:

 Vector2f(6.0, 6.0) Vector2f(2.0, 2.0) Vector2f(6.0, 6.0) Vector2f(44.0, 6.0) Vector2f(2.0, 2.0) Vector2f(44.0, 6.0) 

由于库也提供了一个重载将结果写入另一个向量,我想知道是否可以告诉kotlin不要使用提供的Vector2f.div(Vector2f)方法。

我已经试过向Vector2f提供一个扩展方法,但是被真实成员所影响:

 operator fun Vector2f.div(other: Vector2f): Vector2f = this.div(other, Vector2f()) ^~~ extension is shadowed by a member: public open operator fun div(other: Vector2f!): Vector2f! 

理想情况下,您可以更改Java类,使其运算符功能更好地遵守惯例。 如果您无法修改原始类,那么在使用Kotlin时,您始终可以使用/运算符。

由于它在原始类中,因此无法使用扩展函数覆盖它,原始文件总是优先于它,而不管扩展名是在哪里声明的或者是如何导入的。

你要么必须使用可用的语法,要么你真的不能拥有这个语法,你可以创建一个围绕Vector2f的包装类,它没有公开提供这个名称的功能。

我在这里工作glm端口

对于你的例子,相关的代码在这里

 operator fun div(b: Float) = div(Vec2(), this, b, b) operator fun div(b: Vec2) = div(Vec2(), this, bx, by) fun div(bX: Float, bY: Float, res: Vec2 = Vec2()) = div(res, this, bX, bY) fun div(b: Float, res: Vec2 = Vec2()) = div(res, this, b, b) fun div(b: Vec2, res: Vec2 = Vec2()) = div(res, this, bx, by) fun div_(bX: Float, bY: Float) = div(this, this, bX, bY) infix fun div_(b: Float) = div(this, this, b, b) infix fun div_(b: Vec2) = div(this, this, bx, by) 

背后的逻辑很简单,引用你的示例,最短/最简单的代码:

 val v0 = Vec2(12f) val v1 = Vec2(2f) val res = v0 / v1 

总是创建一个新的实例。 这不知何故遵循也被写在Kotlin文档上的准则。 inc()dec()部分仍然存在(同时它已被修改)。

也是尽可能不容易出错的形式(个人经验..)

对于性能严重的情况,当你不想分配一个新的实例时,妥协就是放弃操作符重载并使用函数形式:

 v0.div(v1, res) 

这意味着,将v0除以v1 ,并将结果res

如果你想让接收者对象变异并直接调用结果:

 v0 div_ v1 

这背后的想法是利用下划线_和等号=以及解释div_ as /=后面的相似性