Java code snippet output explanation required

后端 未结 4 1345
北恋
北恋 2020-12-03 02:03

My code is:

class Foo {
  public int a=3;
  public void addFive() {
    a+=5;
    System.out.print(\"f \");
  }
}

class Bar extends Foo {
  public int a=8;
         


        
相关标签:
4条回答
  • 2020-12-03 02:12

    You cannot override variables in Java, hence you actually have two a variables - one in Foo and one in Bar. On the other hand addFive() method is polymorphic, thus it modifies Bar.a (Bar.addFive() is called, despite static type of f being Foo).

    But in the end you access f.a and this reference is resolved during compilation using known type of f, which is Foo. And therefore Foo.a was never touched.

    BTW non-final variables in Java should never be public.

    0 讨论(0)
  • 2020-12-03 02:16

    With such a question, the SCJP exam is assessing your knowledge of what is known as hiding. The examiner deliberately complicated things to try to make you believe that the behavior of the program depends only on polymorphism, wich it doesn't.

    Let's try to make things a bit clearer as we remove the addFive() method.

    class Foo {
      public int a = 3;
    }
    
    class Bar extends Foo {
      public int a = 8;
    }
    
    public class TestClass {
      public static void main(String[]args) {
        Foo f = new Bar();
        System.out.println(f.a);
      }
    }
    

    Now things are a bit less confusing. The main method declares a variable of type Foo, which is assigned an object of type Bar at runtime. This is possible since Bar inherits from Foo.The program then refers to the public field a of the variable of type Foo.

    The error here would be to believe that the same kind of concept known as overriding applies to class fields. But there is no such a concept for fields: the public field a of class Bar is not overriding the public field a of class Foo but it does what is called hiding. As the name implies, it means that in the scope of the class Bar, a will refer to Bar's own field which has nothing to do with Foo's one. (JLS 8.4.8 - Inheritance, Overriding, and Hiding)

    So, when we are writing f.a, which a are we referring to? Recall that resolution of the field a is done at compile time using the declaring type of the object f, which is Foo. As a consequence, the program prints '3'.

    Now, lets add an addFive() method in class Foo and override it in class Bar as in the exam question. Here polymorphism applies, therefore the call f.addFive() is resolved using not the compile time but the runtime type of object f, which is Bar, and thus is printed 'b '.

    But there is still something we must understand: why the field a, which was incremented by 5 units, still sticks to the value '3'? Here hiding is playing around. Because this is the method of class Bar which is called, and because in class Bar, every a refers to Bar's public field a, this is actually the Bar field which is incremented.

    1) Now, one subsidiary question: how could we access the Bar's public field a from the main method? We can do that with something like:

    System.out.println( ((Bar)f).a );
    

    which force the compiler to resolve the field member a of f as Bar's a field.

    This would print 'b 13' in our example.

    2) Yet another question: how could we work around hiding in addFive() method of class Bar to refer not to the Bar's a field but to its superclass eponimous field ? Just adding the super keyword in front of the field reference does the trick:

    public void addFive() {
      super.a += 5;
      System.out.print("b ");
    }
    

    This would print 'b 8' in our example.

    Note that the initial statement

    public void addFive() {
      this.a += 5;
      System.out.print("b ");
    }
    

    could be refined to

    public void addFive() {
      a += 5;
      System.out.print("b ");
    }
    

    because when the compiler is resolving the field a, it will start to look in the closest enclosing scope from within the method addFive(), and find the Bar class instance, eliminating the need to use explicitely this.

    But, well, this was probably a clue for the examinee to solve this exam question !

    0 讨论(0)
  • 2020-12-03 02:17

    F is a reference of type Foo, and variables aren't polymorphic so f.a refers to the variable from Foo which is 3

    How to verify it?

    To test this you can remove a variable from Foo , it will give you compile time error

    Note: Make member variable private and use accessors to access them


    Also See

    • Why use getters and setters?
    0 讨论(0)
  • 2020-12-03 02:24

    Since you are doing f.a you will get the value of a from the class Foo. if you had called a method to get the value, e.g getA() then you would have gotten the value from the class Bar.

    0 讨论(0)
提交回复
热议问题