Java field hiding for attributes

走远了吗. 提交于 2020-01-13 13:50:14

问题


I just started to learn Java, so please bear with me if the answer is somewhat obvious. I did some research but no avail.

From what I understand, attributes are not overriden but only field hidden. To determine whether the attribute in the superclass or the subclass is used, Java will check the type of the reference.

Then I don't under stand the output here:

public class Super {
    String str = "I'm super!\n";

    public String toString() {
        return str;
    }
}

public class Sub extends Super {
    String str = "I'm sub.\n";
}

public class TestFH {
    public static void main(String[] args) {
        Sub s1 = new Sub();

        System.out.printf(s1.toString());
    }
}

It gives me:

I'm super!

I understand that I can achieve what I want easily via method overriding. I'm just curious about what's happenning under the hood.

Thanks in advance.


回答1:


When you call, s1.toString(), it's finding toString() method defined only in Super class hence using that method as super class methods are available in the sub class. Your super class method toString() is using it's own class variable str (with value initialized in super class) as the return value from the method and hence the behavior i.e. output as I'm super!.

If you want to get the output as I'm sub.\n then you need to reuse the same variable as in the super class and assign the new string value i.e. I'm sub.\n to it. Best option is to use constructors as:

  public class Super {
     String str = "I'm super!\n";

     public Super(String stringValue){
         this.str = stringValue;
     }

     public String toString() {
        return str;
     }
  }

  public class Sub extends Super {
     public Sub(){
       super("I'm sub.\n");
     }
  }

  public class TestFH {
    public static void main(String[] args) {
       Sub s1 = new Sub();
       System.out.printf(s1.toString());
    }
  }



回答2:


You're hiding (shadowing) str in your child class. Since you have not overridden toString() in your child class, the call is being made in the parent class, and it sees the parent's str.

If you did this:

public class Sub extends Super {
    public Sub() {
        this.str = "I'm sub.\n";
    }
}

It would output what you're expecting.




回答3:


This call is using the super class:

Sub s1 = new Sub();
System.out.printf(s1.toString());

The reason is that Sub is not overriding str, it is just declaring another variable that happens to have the same name. In other words, sub is just hiding the variable in Super (data members are not polymorphic).

You could give them different names if they mean different things. Or maybe have the Sub access (or modify) the parent's attribute using a getter method.




回答4:


you're not assigning the string literal, "I'm sub.\n" to the shared superclass field, you're creating a field local to the subclass and assigning it to that instead.

for example,

public class EncapsulationDemo {

    public static void main(String[] args){
        MySuperObject obj = new MySubObject();

        System.out.println(obj); // prints I'm sub.
    }

    private static class MySuperObject{
        String str = "I'm super."; // protected, can be accessed directly 
                                   // by subclasses

        @Override
        public String toString(){
            return str;
        }
    }

    private static class MySubObject extends MySuperObject{
        MySubObject(){
            super();
            str = "I'm sub."; // assign to superclass field
        }
    }
}

for more information, please see Controlling Access to Members of a Class.



来源:https://stackoverflow.com/questions/13984472/java-field-hiding-for-attributes

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!