Search code examples
javainheritancefieldmember-hiding

superclass with private static field and subclass calls a method that changes the field, Why doesn't the field change?


public class B {

    private static  boolean goo=true;

    protected static boolean foo() {
        goo=!goo;
        return goo;
    }

    public String bar="Base:"+foo();

    public static void main(String[] args)  {
        B base=new A();
        System.out.println("Base:"+goo);//***prints Base:true***
    }
}

public class A extends B{
    public String bar="Sub:"+foo();
}

Why does the program print true instead of false, I don't understand why goo didn't change after foo() was called. goo isn't hidden because it is a private field. the static field before creating an object is true, then when foo occurs isn't it supposed to change goo in Heap?


Solution

  • The reason is well explained inPanz0r's answer but what you don't see is that you have two variable call bar, one in A one in B.

    If you add a method to print the instance members in both class (and A will also print is super class):

    public class Main {
    
        public static void main(String[] args) {
            B base = new A();
            System.out.println(base);
        }
    }
    
    class B {
    
        private static boolean goo = true;
    
        protected static boolean foo() {
            goo = !goo;
            return goo;
        }
    
        public String bar = "Base:" + foo();
    
        @Override
        public String toString() {
            return bar; //print the variable B.bar
        }
    }
    
    class A extends B {
        public String bar = "Sub:" + foo();
    
        @Override
        public String toString() {
            //print the instance B and the variable A.bar
            return super.toString() + "\n" + bar;
        }
    }
    

    You will see that both bar exist in an instance A

    Base:false
    Sub:true

    You could access B.bar variable using super.bar if the accessibility allowed it but it is private in your case.

    A solution would be to use a constuctor B that will accept a value and concatenate the result of foo.

    public String bar;
    
    public B(){
        this("Base: ");
    }
    
    protected B(String source){ //protected to prevent anybody to use it directly
        bar = source + foo();
    }
    

    And in A

    public A(){
        super("Sub: ");
    }
    

    Only the creation of B will call foo so you get the result :

    Sub: false

    Let's check with this :

    System.out.println(new A().bar);
    System.out.println(new B().bar);
    System.out.println(new A().bar);
    

    Sub: false
    Base: true
    Sub: false