为什么内部 class 方法会隐藏所有具有相同名称的封闭 class 方法?

Why does an inner class method hide all the enclosing class methods with the same name?

考虑下面的 java 代码:

class Enclosing {
    void method(){}
    void method(String str){}

    class Inner {
        void method(){}
    }   
}

我正在看一本书,它告诉我 Inner.method() 会隐藏 Enclosing.method() 的两个版本,这意味着如果我在 [=37= 的某处调用 method(aString) 是错误的] Inner.

为什么语言是这样设计的?

更新:
根据@Debosmit Ray 给出的答案,与shadowing有关。我已阅读文档并了解它是什么。

仍然让我困惑的是为什么方法隐藏是基于方法名称而不是方法签名?

因为Scope, Method, Variables and constants 在全局方法和变量上制作影子...

非静态嵌套 class 或内部 classes 被用作逻辑分组仅在一个地方使用的 classes 的一种方式;它使代码更具可读性并促进 封装.

来自 [docs],

If a declaration of a type (such as a member variable or a parameter name) in a particular scope (such as an inner class or a method definition) has the same name as another declaration in the enclosing scope, then the declaration shadows the declaration of the enclosing scope.

这里的阴影意味着如果你在外部 class 中有一个变量 x 并且在内部 class 中有另一个变量 x,修改 x 在内部 class 不会影响 在外部 class.

x

我很喜欢这个问题和你提出的观点。我的解释对你理解有帮助吗?

如果您为您的问题找到了正确的标签,您应该已经更好地理解了这个概念!在 SO 上查看 shadowing 的标签信息。

In computer programming, shadowing occurs when a variable declared within a certain scope (decision block, method or inner class) has the same name as a variable declared in an outer scope. This can lead to confusion, as it may be unclear which variable subsequent uses of the shadowed variable name refer to, which depends on the name resolution rules of the language.

One of the first languages to introduce variable shadowing was ALGOL, which first introduced blocks to establish scopes. It was also permitted by many of the derivative programming languages including C++ and Java.

The C# language breaks this tradition, allowing variable shadowing between an inner and an outer class, and between a method and its containing class, but not between an if-block and its containing method, or between case statements in a switch block.

Wikipedia link(虽然提供的不多)


Why is the language designed like that?

让我给你一个现实世界的类比,以帮助你理解。

想想一个 建筑 (1),它有一个名为 Turn on lights (3) 的按钮。当你按下那个按钮时,它会打开大楼里的所有灯。现在想想那个建筑物内的 隔间 (2)。在那个 隔间 中有一个小 lamp,还有一个名为 Turn on lights 的类似按钮。现在,当您按下该按钮时,您希望它做什么——打开 大楼 的所有灯,或者只打开 大楼中的 lamp隔间?可能是后者。虽然这两个按钮具有相同的 name (4),但它们的行为因 place (5).

而异

现在将此类比应用于 OOP。多看一遍斜体的字,匹配起来!

  1. 建筑 --> 封闭class
  2. 小隔间 --> 内class
  3. 开灯 --> 方法
  4. 名称 --> 方法name/signature
  5. 地点 --> 范围

请注意,该类比并未考虑 OOP 的许多其他概念,但我认为它可能有助于您理解问题的 原因 部分。


回复更新:

What still confusing me is why method shadowing is based on method name not method signature?

您的问题似乎无效。你很快就会明白这一点。

你说隐藏不是基于方法签名。如果你的意思是:"if inner class method has same signature as enclosing class method, then shadowing doesn't take place",那你就错了。尝试在内部 class 中创建另一个方法,例如 void method(String str),然后在内部 class 中调用该方法。你会看到它明显有阴影。

而当您在内部 class 中调用 method(aString) 时出现错误的原因完全是另外一回事——方法 method(String str) 甚至不存在于内部class范围。

如果您需要进一步说明,请随时联系我们。

这称为遮蔽

根据JLS 6.4.1

Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity.

编程语言有影子很方便。例如,在构造函数中,可以让参数和class字段变量同名,并用this区分。

class Person {
    private String name;
    Person (String name) {
        this.name = name;
    }
}

在某些其他语言中,变量可能会被代码块遮蔽,例如,在 C++ 中,您可以编写如下代码:

// C++ code:
int i = 10;

for(int i = 0; i != 5; ++i) {
    // use i from 0 to 4 here
}

for(int i = 100; i > 0; --i) {
    // use i from 100 to 1 here
}

// the first i is still 10 and can be used here

循环里面的变量i和外面的i不一样。

Why is the language designed like that?

正如您在构造函数示例中看到的那样,有时变量可能真的意味着同一件事。阴影使您可以使用相同的名称而无需创建新名称,这有点麻烦,因为命名变量并不简单。

并且在循环示例中,在 Java 中不受支持,但它是展示阴影优势的一个很好的示例,有时您可以在代码块中声明一些临时变量而不修改块外的其他变量。


Why method shadowing is based on method name not method signature?

JLS 15.12中有关于方法调用的解释

可以看到,在第1步中,编译器会搜索可以调用这个方法的作用域。最后找到了Enclosing.Inner.

在第 2 步,编译器将检查方法的签名。

因此,编译器会将Enclosing.Inner.method()作为唯一可以调用的方法。这就是为什么你不能直接调用 Enclosing.method(String str),即使它们有不同的方法签名。

如果你想在Innerclass里面调用Enclosing.method(String str),你可以这样做:

class Inner {
    void method(){
        Enclosing.this.method("test");
    }
}