【问题标题】:Static member method to Instance member method redeclaration allowed for Interface-Class but not for Class-Class or Interface-Interface [duplicate]Interface-Class允许静态成员方法到Instance成员方法重新声明,但Class-Class或Interface-Interface不允许[重复]
【发布时间】:2021-12-18 12:15:57
【问题描述】:

考虑以下 sn-p:

interface Super{
    public static void doIt(){}
}
class Sub implements Super{
    public void doIt(){}
}
  • 这里我声明了一个静态成员方法,它被重新声明为子类中的实例方法。
  • 编译器允许这样做 - 但是当我对超类和子类类型执行相同操作时 - 这会导致编译错误:
class Super{
    public static void doIt(){}
}
class Sub extends Super{
    public void doIt(){}
}
  • 相同的原因是什么? - 理想情况下,访问子类的方式基本相同 - 那么为什么会有这种限制?

【问题讨论】:

  • 我怀疑编译器正在阻止一个错误。因为可以在实例上调用超类上的静态方法(是的,带有警告),这最终可能会产生误导……subObject.doIt() 将调用哪个方法?如果Super 是接口,则不能使用subObject.doIt() 调用Super.doIt(),编译器已经禁止这样做。
  • 作为类实例一部分的成员被覆盖(即公共和受保护),静态成员不是类实例的一部分,它是实际类的一部分。

标签: java inheritance java-8 interface static-methods


【解决方案1】:

这样做的原因是 Java 允许以非静态方式调用 static 方法。考虑这个例子:

public class MyClass {
    public static void sayHello() {
    }

    public void test() {
        this.sayHello();
    }
}

这将产生编译器警告(MyClass 类型的静态方法 sayHello() 应该以静态方式访问),但它会在运行时正确编译和调用静态方法.

这就是为什么下面的代码由于歧义而无法编译的原因(MyClass 类型中的重复方法test()):

public class MyClass {
    public static void test() {
    }

    public void test() {
    }
}

编译错误的原因是,如果你写如下,编译器无法知道调用哪个方法,因为它允许以非静态方式调用static方法:

public class MyClass {
    public static void test() {
    }

    public void test() {
    }

    public void execute() {
        this.test();
    }
}

出于同样的原因,在父类中不可能有static test() 方法——同样的规则适用。在 Java 中可以调用 static 超类的方法,无论是否有条件:

public class Super {
    public static void test() {
    }
}

public class Sub extends Super {
    public void execute() {
        this.test();
    }
}

public class Sub {
    public void execute() {
        test();
    }
}

this.test() 的调用会产生警告,但会在运行时起作用。

对于接口中的static 方法,上面的示例将不起作用,因为编译器会强制您以限定的方式调用接口的static 方法(编辑:因为它们没有被继承)。以下将工作(方法 interfaceStatic() 未定义为 Sub 类型):

public interface Interface {
    public static void interfaceStatic() {  
    }
}

public class Sub implements Interface {
    public void test() {
        interfaceStatic();
    }
}

为了调用interfaceStatic(),调用必须像这样限定:

public class Sub implements Interface {
    public void test() {
        Interface.interfaceStatic();
    }
}

这就是在接口中定义static方法和在super类中定义的区别:调用方式。如果你实现了多个接口,这些接口都有一个签名相同的static方法,编译器就无法知道调用哪一个。

这就是为什么允许在实现的接口中定义具有相同签名的static 方法,但不能在父类中定义的原因。

【讨论】:

  • 一个静态接口方法,当它是作用域时,仍然可以在没有限定符的情况下调用,例如public interface Interface { public static void interfaceStatic() {} default void instanceMethod() { interfaceStatic(); /* but not this.interfaceStatic(); */ } }。同样,当其他类具有适当的import static …; 语句时,它可以将其用作interfaceStatic();。但是静态接口方法不继承,所以它们不在实现类的范围内,除非它们包含import static …; 语句。由于实现没有继承它,所以没有冲突。
  • @Holger 是的,这是真的。但这是一个不同的故事,不在问题的范围内。如果通过import static 显式导入,则必须在导入类​​中自己处理冲突的方法签名。问题是关于“重复定义”错误。如您所知,static 方法属于类,而不是实例。如果 Java 对所有 instance 成员强制使用 this 关键字,则根本没有问题,因为编译器总是知道您指的是什么(类或实例成员)。例如。 TypeScript 允许 OP 的要求。
  • OP 想知道为什么声明 public void doIt(){}class Sub implements Super 中被接受,答案是,因为 Sub 没有从 Super 继承 public static void doIt(){} 方法。如果你试图在Super 中声明该方法,你仍然会得到一个错误,即interface Super{ public static void doIt(){} public void doIt(); } 无法编译,尽管你不能为this.doIt() 接口方法做this.doIt()。是否能区分调用无关紧要。
  • 你倒退了。该方法未被继承的事实是所有其他事情的原因,而不仅仅是它们所暗示的,因此是为什么问题的答案。
  • 问题不是“为什么 Java 不允许这样做”,而是“为什么在类实现接口的情况下这个声明是可能的 ”,而答案正是“因为在这种情况下,该类没有继承矛盾的方法”。您正在尝试回答一个尚未被问到的问题。
猜你喜欢
  • 1970-01-01
  • 2020-09-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-27
  • 1970-01-01
相关资源
最近更新 更多