• 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

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

  • 相关阅读:
    原码、反码、补码,计算机中负数的表示
    java 解惑系列
    (转载) 深入JVM学习笔记-安全性
    理解Java对象序列化
    关于Arrays.asList 函数的一些 陷阱
    JAVA设计模式之单例模式 (转载)
    Educational Codeforces Round 76 D
    总结
    bzoj3531: [Sdoi2014]旅行 (树链剖分 && 动态开点线段树)
    bzoj3626: [LNOI2014]LCA (树链剖分)
  • 原文地址:https://www.cnblogs.com/herd/p/16018142.html
Copyright © 2020-2023  润新知