9.14. (Optional) Hiding Data Fields and Static Methods |
This section is marked optional because hidden instance/static data fields and static methods are rarely useful, and they should not be used, for the sake of simplicity and clarity. You may skip this section now and consult it for reference in the future.
You can override an instance method, but you cannot override a data field (instance or static) or a static method. If you declare a data field or a static method in a subclass with the same name as one in the superclass, the one in the superclass is hidden, but it still exists. The two data fields or static methods are independent. You can reference the hidden data field or static method using the keyword super in the subclass. The hidden field or method can also be accessed via a reference variable of the superclass's type.
When invoking an instance method from a reference variable, the actual class of the object referenced by the variable decides which implementation of the method is used at runtime . When accessing a data field or a static method, the declared type of the reference variable decides which field or static method is used at compile time . This is the key difference between invoking an instance method and accessing a data field or a static method.
Listing 9.10 demonstrates the effect of hiding data fields and static methods.
1 public class HidingDemo { 2 public static void main(String[] args) { 3 A x = new B(); 4 5 // Access instance data field i 6 System.out.println( "(1) x.i is " + x.i); 7 System.out.println( "(2) (B)x.i is " + ((B)x).i); 8 9 // Access static data field j 10 System.out.println( "(3) x.j is " + x.j ); 11 System.out.println( "(4) ((B)x).j is " + ((B)x).j ); 12 13 // Invoke static method m1 14 System.out.println( "(5) x.m1() is " + x.m1() ); 15 System.out.println( "(6) ((B)x).m1() is " + ((B)x).m1() ); 16 17 // Invoke instance method m2 18 System.out.println( "(7) x.m2() is " + x.m2() ); 19 System.out.println( "(8) x.m3() is " + x.m3() ); 20 } 21 } 22 23 class A { 24 public int i = 1 ; 25 public static int j = 11 ; 26 27 public static String m1() { 28 return "A's static m1" ; 29 } 30 31 public String m2() { 32 return "A's instance m2" ; 33 } 34 35 public String m3() { 36 return "A's instance m3" ; 37 } 38 } 39 40 class B extends A { 41 public int i = 2 ; 42 public static int j = 12 ; 43 44 public static String m1() { 45 return "B's static m1" ; 46 } 47 48 public String m2() { 49 return "B's instance m2" ; 50 } 51 } |
The printout of the program is:
(1) x.i is 1 (2) (B)x.i is 2 (3) x.j is 11
(4) ((B)x).j is 12 (5) x.m1() is A ' s static m1 (6) ((B)x).m1() is B ' s static m1 (7) x.m2() is B ' s instance m2 (8) x.m3() is A ' s instance m3
Here are the explanations :
x.i is 1 because x 's declared type is class A .
To use i in class B , you need to cast x to B using ((B)x).i .
x.j is 11 because x 's declared type is class A . x.j is better written as A.j .
To use j in class B , you need to cast x to B using ((B)x).j . ((B)x).j is better written as B.j .
x.m1() invokes the static m1 method in A because x 's declared type is A . x.m1() is better written as A.m1() .
((B)x).m1() invokes the static m1 method in B because the type for (B)x is B . ((B)x).m1() is better written as B.m1() .
x.m2() invokes the m2 method in B at runtime because x actually references to the object of class B .
x.m3() invokes the m3 method in A at runtime because m3 is implemented in A .
Note
A static method or a static field can always be accessed using its declared class name, regardless of whether it is hidden or not. |