The following examples illustrate some (possibly subtle) points about field declarations.
class Point { static int x = 2; }
class Test extends Point { static double x = 4.7; public static void main(String[] args) {
new Test().printX(); } void printX() { System.out.println(x + " " + super.x); } }
4.7 2
because the declaration of x
in class Test
hides the definition of x
in class Point
,
so class Test
does not inherit the field x
from its superclass Point
. Within the
declaration of class Test
, the simple name x
refers to the field declared within
class Test
. Code in class Test
may refer to the field x
of class Point
as super.x
(or, because x
is static
, as Point.x
). If the declaration of Test.x
is deleted:
class Point { static int x = 2; }
class Test extends Point { public static void main(String[] args) { new Test().printX(); } void printX() { System.out.println(x + " " + super.x); } }
then the field x
of class Point
is no longer hidden within class Test
; instead, the
simple name x
now refers to the field Point.x
. Code in class Test
may still refer
to that same field as super.x
. Therefore, the output from this variant program is:
2 2
This example is similar to that in the previous section, but uses instance variables rather than static variables. The code:
class Point { int x = 2; }
class Test extends Point { double x = 4.7; void printBoth() { System.out.println(x + " " + super.x); } public static void main(String[] args) { Test sample = new Test(); sample.printBoth(); System.out.println(sample.x + " " +
((Point)sample).x); } }
4.7 2 4.7 2
because the declaration of x
in class Test
hides the definition of x
in class Point
,
so class Test
does not inherit the field x
from its superclass Point
. It must be
noted, however, that while the field x
of class Point
is not inherited by class
Test
, it is nevertheless implemented by instances of class Test
. In other words,
every instance of class Test
contains two fields, one of type int
and one of type
float
. Both fields bear the name x
, but within the declaration of class Test
, the
simple name x
always refers to the field declared within class Test
. Code in
instance methods of class Test
may refer to the instance variable x
of class Point
as super.x
.
Code that uses a field access expression to access field x
will access the field named x
in the class indicated by the type of reference expression. Thus, the expression sample.x
accesses a float
value, the instance variable declared in class Test
, because the type of the variable sample is Test
, but the expression ((Point)sample).x
accesses an int
value, the instance variable declared in class Point
, because of the cast to type Point
.
If the declaration of x
is deleted from class Test
, as in the program:
class Point { static int x = 2; }
class Test extends Point { void printBoth() { System.out.println(x + " " + super.x); } public static void main(String[] args) { Test sample = new Test(); sample.printBoth(); System.out.println(sample.x + " " +
((Point)sample).x); } }
then the field x
of class Point
is no longer hidden within class Test
. Within
instance methods in the declaration of class Test
, the simple name x
now refers to
the field declared within class Point
. Code in class Test
may still refer to that
same field as super.x
. The expression sample.x
still refers to the field x
within
type Test
, but that field is now an inherited field, and so refers to the field x
declared in class Point
. The output from this variant program is:
2 2 2 2
A class may inherit two or more fields with the same name, either from two interfaces or from its superclass and an interface. A compile-time error occurs on any
attempt to refer to any ambiguously inherited field by its simple name. A qualified
name or a field access expression that contains the keyword super
(§15.10.2) may
be used to access such fields unambiguously. In the example:
interface Frob { float v = 2.0f; }
class SuperTest { int v = 3; }
class Test extends SuperTest implements Frob { public static void main(String[] args) { new Test().printV(); } void printV() { System.out.println(v); } }
the class Test
inherits two fields named v
, one from its superclass SuperTest
and
one from its superinterface Frob
. This in itself is permitted, but a compile-time
error occurs because of the use of the simple name v
in method printV
: it cannot
be determined which v
is intended.
The following variation uses the field access expression super.v
to refer to the field named v
declared in class SuperTest
and uses the qualified name Frob.v
to refer to the field named v
declared in interface Frob
:
interface Frob { float v = 2.0f; }
class SuperTest { int v = 3; }
class Test extends SuperTest implements Frob { public static void main(String[] args) { new Test().printV(); } void printV() { System.out.println((super.v + Frob.v)/2); } }
2.5
Even if two distinct inherited fields have the same type, the same value, and are both final
, any reference to either field by simple name is considered ambiguous and results in a compile-time error. In the example:
interface Color { int RED=0, GREEN=1, BLUE=2; }
interface TrafficLight { int RED=0, YELLOW=1, GREEN=2; }
class Test implements Color, TrafficLight { public static void main(String[] args) { System.out.println(GREEN); // compile-time error System.out.println(RED); // compile-time error } }
it is not astonishing that the reference to GREEN
should be considered ambiguous,
because class Test
inherits two different declarations for GREEN
with different
values. The point of this example is that the reference to RED
is also considered
ambiguous, because two distinct declarations are inherited. The fact that the two
fields named RED
happen to have the same type and the same unchanging value
does not affect this judgment.
If the same field declaration is inherited from an interface by multiple paths, the field is considered to be inherited only once. It may be referred to by its simple name without ambiguity. For example, in the code:
public interface Colorable { int RED = 0xff0000, GREEN = 0x00ff00, BLUE = 0x0000ff; }
public interface Paintable extends Colorable { int MATTE = 0, GLOSSY = 1; }
class Point { int x, y; }
class ColoredPoint extends Point implements Colorable { . . . }
class PaintedPoint extends ColoredPoint implements Paintable { . . .RED
. . . }
the fields RED
, GREEN
, and BLUE
are inherited by the class PaintedPoint
both
through its direct superclass ColoredPoint
and through its direct superinterface
Paintable
. The simple names RED
, GREEN
, and BLUE
may nevertheless be used
without ambiguity within the class PaintedPoint
to refer to the fields declared in
interface Colorable
.