static Fields

8.3.1.1. static Fields

If a field is declared static, there exists exactly one incarnation of the field, no matter how many instances (possibly zero) of the class may eventually be created. A static field, sometimes called a class variable, is incarnated when the class is initialized (§12.4).

A field that is not declared static is called an instance variable, and sometimes called a non-static field. Whenever a new instance of a class is created (§12.5), a new variable associated with that instance is created for every instance variable declared in that class or any of its superclasses.

The declaration of a class variable introduces a static context (§8.1.3), which limits the use of constructs that refer to the current object. Notably, the keywords this and super are prohibited in a static context (§15.8.3§15.11.2), as are unqualified references to instance variables, instance methods, and type parameters of lexically enclosing declarations (§6.5.5.1§6.5.6.1§15.12.3).

References to an instance variable from a static context or a nested class or interface are restricted, as specified in §6.5.6.1.

 

Example 8.3.1.1-1. static Fields

class Point {
    int x, y, useCount;
    Point(int x, int y) { this.x = x; this.y = y; }
    static final Point origin = new Point(0, 0);
}
class Test {
    public static void main(String[] args) {
        Point p = new Point(1,1);
        Point q = new Point(2,2);
        p.x = 3;
        p.y = 3;
        p.useCount++;
        p.origin.useCount++;
        System.out.println("(" + q.x + "," + q.y + ")");
        System.out.println(q.useCount);
        System.out.println(q.origin == Point.origin);
        System.out.println(q.origin.useCount);
    }
}

 

This program prints:

(2,2)
0
true
1

 

 

showing that changing the fields xy, and useCount of p does not affect the fields of q, because these fields are instance variables in distinct objects. In this example, the class variable origin of the class Point is referenced both using the class name as a qualifier, in Point.origin, and using variables of the class type in field access expressions (§15.11), as in p.origin and q.origin. These two ways of accessing the origin class variable access the same object, evidenced by the fact that the value of the reference equality expression (§15.21.3):

q.origin==Point.origin

 

is true. Further evidence is that the incrementation:

p.origin.useCount++;

 

causes the value of q.origin.useCount to be 1; this is so because p.origin and q.origin refer to the same variable.

 

 

 

 

Example 8.3.1.1-2. Hiding of Class Variables

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

 

 

This program 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

 

 

 

Example 8.3.1.1-3. Hiding of Instance Variables

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

 

 

This program 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 double. 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 double 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

 

 

 

参考:https://docs.oracle.com/javase/specs/index.html

https://docs.oracle.com/javase/specs/jls/se17/html/jls-8.html#jls-8.3.1.1

####################################

posted @ 2022-03-17 17:19  西北逍遥  阅读(92)  评论(0编辑  收藏  举报