隐藏(hide)和重写(override)和遮掩(obscure)遮蔽(shadow)和重载(overload)

重写(override)

一个实例方法可以overide在其超类中可以访问到的具有相同签名的所有方法,从而可以动态分派(dynamic dispatch),VM基于运行时类型来选择要调用的覆写方法。

1
2
3
4
5
6
7
8
class Base {
public void f() {
}
}
class Derived extends Base {
public void f() {
} // overrides Base.f()
}

隐藏 hide

一个域,静态方法,或成员类型可以分别被隐藏(hide)在其超类可以访问到的具有相同名字的所有域、静态方法或成员类型。hide几个成员将阻止其被继承。
// 错误样例

1
2
3
4
5
6
7
8
class Base {
public static void f() {
}
}
class Derived extends Base {
private static void f() {
} // hides Base.f()
}

// 正确样例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Base {
static int a = 1;
int b = 3;
public static void f() {
System.out.println("Base");
}
}
class Derived extends Base {
static int a = 2;
int b = 4;
public static void f() {
System.out.println("Derived");
} // hides Base.f()
}
public class Hide {
public static void main(String[] args) {
Base.f();
Derived.f();
System.out.println(Base.a);
System.out.println(Derived.a);
System.out.println((new Base()).b);
System.out.println((new Derived()).b);
System.out.println(((Base) (new Derived())).b);
}
}

重载(overload)

在某个类中的方法可以重载(overload)另一个方法,只要它们具有相同的名字和不同的签名。由调用所指定的重载方法是在编译期选定的。

遮蔽(shadow)

一个变量、方法或类型可以分别遮蔽(shadow)在一个闭合的文本范围内的具有相同名字的所有变量、方法或类型。如果一个实体被遮蔽了,那么你用它的简单名是无法引用到它的;根据实体的不同,有时你根本就无法引用到它。

1
2
3
4
5
6
7
class WhoKnows {
static String sentence = "I don't know.";
public static void main(String[] args) {
String sentence = "I know!"; // shadows static field
System.out.println(sentence); // prints local variable
}
}

  1. 编译器在选择在运行期被调用的方法时,所做的第一件事就是在肯定能找到该方法的范围内挑选。编译器将在包含具有恰当名字的方法的最小闭合范围内挑选,下例中就是ImportDuty类,它包含了从Object继承的方法toString。
  2. 导入的toString方法被继承的toString方法所遮蔽(shadow)
  3. 本身就属于某个范围的成员在该范围内与静态导入相比具有优先权。
    以下代码无法被编译通过
    1
    2
    3
    4
    5
    6
    7
    8
    9
    import static java.util.Arrays.toString;
    class ImportDuty {
    public static void main(String[] args) {
    printArgs(1, 2, 3, 4, 5);
    }
    static void printArgs(Object... args) {
    System.out.println(toString(args));
    }
    }

遮掩(obscure)

一个变量可以遮掩具有相同名字的一个类型,只要它们都在同一个范围内:如果这个名字被用于变量与类型都被许可的范围,那么它将引用到变量上。相似地,一个变量或一个类型可以遮掩一个包。遮掩是唯一一种两个名字位于不同的名字空间的名字重用形式,这些名字空间包括:变量、包、方法或类型。

1
2
3
4
5
6
7
8
// 变量遮掩了类型
public class Obscure {
static String System; // Obscures type java.lang.System
public static void main(String[ ] args) {
// Next line won't compile: System refers to static field
System.out.println(”hello, obscure world!“);
}
}

当一个变量和一个类型具有相同的名字,并且他们位于相同的作用域时,变量名具有优先权 JLS 6.5.2,变量将遮掩(obscure)类型名。相似地,变量名和类型名可以遮掩包名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ShadowOfGray {
public static void main(String[] args) {
System.out.println(X.Y.Z); // 输出结果White
}
}
class X {
static class Y {
static String Z = "Black";
}
static C Y = new C();
}
class C {
String Z = "White";
}