在rust中,我们可以做这样的事情:
trait MyTrait { fn my_func(); } struct MyStruct {} impl MyTrait for MyStruct { fn my_func() { // this gets invoked } } fn my_func<B: MyTrait>() { // This here B::my_func(); } fn main() { my_func::<MyStruct>(); }
在java中,我们不能做这样的事情:
interface MyInterface { public static void myFunc() { // This gets invoked } } class MyClass implements MyInterface { public static void myFunc() { } } public class Main { static <T extends MyInterface> void myFunc() { // This here T.myFunc(); } public static void main(String[] args) { Main.<MyClass>myFunc(); } }
现在还有其他问题,关于为什么 java 不允许重写/强制执行 java 中的静态方法,但是这个特定示例是否因为单态化与类型删除而不起作用>?我试图了解更深层的原因。 我的猜测是,由于类型删除后只有一种实现,并且需要编译静态调用,因此它不起作用。这是真正的原因吗??
最佳答案
正如您所指出的,会发生类型删除,并且 Java 泛型可以被视为语法糖。它用于类型检查,但在 resulting byte code, it will be replaced 中.
如果它是未绑定(bind)类型,它将被替换为Object
,但在您的示例中,它是绑定(bind)类型(T extends MyInterface
),因此它将替换为 MyInterface
。这就是 MyInterface.myFunc
被调用的原因。
为什么编译器不像 Rust 或 C++ 那样解析它?我认为这是可能的,所以我只能推测 Java 中的设计决策。 Java 本质上比 Rust 更加动态。新类可以在注释处理期间定义,但也可以动态创建。该属性不能很好地适应编译时解析,因为编译器无法在编译时知道所有类。
Java 主要是面向对象的语言,而 Rust 和 C++ 更强调编译阶段。尽管Java是静态类型的,但它更加动态并且在运行时完成更多工作。这使得它更加灵活,但牺牲了性能。
表达您提供的 Rust 代码的“Java 方式”是使用普通函数而不是 static
函数。效果类似,但最终会得到动态调度。 Rust 像 C++ 一样遵循零开销原则,因此被迫使用动态调度将违反该原则。另一方面,在 Java 中,这不是设计目标。
通常,JIT 仍然应该能够对其进行优化(即消除动态调度并内联代码)。但没有像等效的 Rust(或 C++)那样的保证,一切都在编译时决定。
关于java - Rust 与 Java 静态方法以及泛型类型参数的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68613825/