8.3.3 Examples of Field Declarations

The following examples illustrate some (possibly subtle) points about field declarations.

8.3.3.1 Example: Hiding of Class Variables

The example:


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); } }

produces the output:

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

8.3.3.2 Example: Hiding of Instance Variables

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); } }

produces the output:


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

8.3.3.3 Example: Multiply Inherited Fields

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);
	}
}

It compiles and prints:

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.

8.3.3.4 Example: Re-inheritance of Fields

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.