Interface-Class允许静态成员方法到Instance成员方法重新声明,但Class-Class或Interface-Interface不允许[重复]

Posted

技术标签:

【中文标题】Interface-Class允许静态成员方法到Instance成员方法重新声明,但Class-Class或Interface-Interface不允许[重复]【英文标题】:Static member method to Instance member method redeclaration allowed for Interface-Class but not for Class-Class or Interface-Interface [duplicate] 【发布时间】: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(),编译器已经禁止这样做。 作为类实例一部分的成员被覆盖(即公共和受保护),静态成员不是类实例的一部分,它是实际类的一部分。 【参考方案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 不允许这样做”,而是“为什么在类实现接口的情况下这个声明是可能的 ”,而答案正是“因为在这种情况下,该类没有继承矛盾的方法”。您正在尝试回答一个尚未被问到的问题。

以上是关于Interface-Class允许静态成员方法到Instance成员方法重新声明,但Class-Class或Interface-Interface不允许[重复]的主要内容,如果未能解决你的问题,请参考以下文章

静态方法中只允许访问静态数据,那么,如何在静态方法中访问类的实例成员(即没有附加static关键字的字段或方法)?

java中静态方法和实例方法的区别

静态方法和实例方法的区别

静态方法和实例方法的区别(转)

java 静态方法和实例方法的区别

JAVA 静态方法和实例方法的区别 (图表)