有些术语因为翻译+本身含义模糊+使用者水平问题显得混乱是正常的。对于 Java,我觉得参考 JLS 译本里的翻译是一个不错的选择。
我们需要明确这几个可能互相混淆的概念:隐藏(Hiding)、覆盖(重写,Override)、重载(Overload)、遮蔽(Shadowing)以及遮掩(Obscuring)。
什么是遮蔽(Shadowing)?JLS §6.4.1 中是这样描述的:Some declarations may beshadowedin 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.
遮蔽指一个声明在其作用域内的部分地方因为同名的声明而无法直接访问的情况。譬如方法的参数以及局部变量的声明会遮蔽住同名的类成员变量,import 其他类型会遮蔽住同包下的其他同名的类型。
什么是遮掩(Obscuring)?JLS §6.4.2 中是这样描述的:A simple name may occur in contexts where it may potentially be interpreted as the name of a variable, a type, or a package. In these situations, the rules of§6.5specify that a variable will be chosen in preference to a type, and that a type will be chosen in preference to a package. Thus, it is may sometimes be impossible to refer to a type or package via its simple name, even though its declaration is in scope and not shadowed. We say that such a declaration isobscured.
遮掩指当一个简单名可以被同时解释为变量名、类型名或包名时,因为变量名优先于类型名,类型名优先于包名,所以导致一些名称无法直接访问的情况。譬如我们同时有叫做 org 的变量和叫做 org 的包,那么你使用 org 时它会被优先解释为变量,这个时候我们需要以来 import 来避免这种情况。
与遮蔽和遮掩对多种的声明都可能发生不同,隐藏会发生在域(Field)以及方法上,重载和覆盖只会发生在方法上。If two methods of a class (whether both declared in the same class, or both inherited by a class, or one declared and one inherited) have the same name but signatures that are not override-equivalent, then the method name is said to beoverloaded.
当一个类中的两个同名方法不是覆盖等价(override-equivalent,JLS §8.4.2)的时候,该方法名就会被重载(Overload)。互相重载的几个方法依然是多个方法,当我们调用它们的时候,Java 编译器会通过实际参数类型、参数数量,按照一定的规则(JLS 15.12.2)来确定实际调用的方法。
覆盖(重写,Override,JLS §8.4.8.1)指的是子类型中与直接超类中非 private 实例方法(若与超类不在同一包中,包可见性的方法也不会被覆盖)同名,并且签名是这个超类实例方法的子签名(JLS §8.4.2)的实例方法会把超类中的方法所“覆盖”住的行为。当子类覆盖了超类方法后,除非使用 super 关键字访问超类中被覆盖的方法,否则实际访问到的总是子类中的方法。覆盖在 oop 中是相当重要的一个概念。
隐藏(Hiding,JLS §8.4.8.2)则会发生在继承的时候。对于域,如果子类包含了同名的域,无论是否是 static,超类的域都会被隐藏,只能通过 super(非静态域)或者限定名(静态域)来访问超类中的域;对于方法,只有静态方法才会被隐藏,子类中签名是超类中同名静态方法子签名的静态方法会隐藏超类中的同名方法。
对于这些术语,最权威的解释就是 Java 语言规范(The Java® Language Specification,JLS),如果真的有不确定的概念,首先应该想到的就是通过 JLS 来查询这个概念。如果对方对概念不明晰误用了名称,或者是因为翻译的不准确性使用了一些少见的译名,你也应该要有能力通过对方的描述判断出他所表达的实际概念,这样才能轻松的和他人交流。
说完了概念,再来说说题目中的那些截图。
这里对隐藏(Hiding)和覆盖(Override)发生了混淆,当然也有可能这个问题的题主自己也是糊的。变量(域)是不会发生 Override 的,只可能发生了隐藏(Hiding)。
@CNife 的回答主要是没有弄清楚这几个名词的翻译,对于这几个概念他应该是懂的。第一段里说的应该是 父类静态成员不能被覆盖(Override),但是可以被子类隐藏(Hiding)。
这个文章的作者是真的自己都没搞清楚这几个概念就跑出来坑人,它的文章里有好几点大的错误:覆盖(重写)不要求子类方法和超类方法一样,要求的只是子类方法是超类方法的子签名。简单来说,子类方法只要参数类型和超类中是逆变的,返回值是类型是协变的,参数个数相同名称相同,那么就能发生覆盖。
重载虽然能发生在子类方法和子类继承来的超类方法间,但是并没有要求非要如此。
static 对于静态域的含义勉强能像他所说的那样,分配的内存一直存在,但是这个描述放在静态方法上就完全错了。
JVM 一般来说对静态和非静态方法本身分配内存的规则都是一样的。至于方法指向的都是同一块内存中的数据……hmmm,我也不知道他想表达的是什么。
最后那段话其实也能说的过去,但是讨论给方法分配的内存显得太怪异了,我认为他还是没搞清楚这个概念。Java的术语为何如此混乱?www.zhihu.com
这个答案有一点点问题,问题出在这:
实际上 JLS 里是存在隐藏这个术语的,不过的确不是 Override 的翻译。