Java属���的字段隐藏

4

我刚开始学习Java,所以如果答案显而易见请见谅。我做了一些研究但没有找到解决方案。

据我了解,属性不被覆盖,只是被隐藏。为了确定在超类或子类中使用哪个属性,Java将检查引用的类型。

那么我不明白这里的输出:

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

它给了我:

I'm super!

我知道我可以通过方法覆盖轻松实现我的目标。我只是好奇在幕后发生了什么。
提前致谢。

你期望输出什么? - Rohit Jain
@RohitJain 我本来期望输出"I'm sub.",因为我是通过子类引用(即s1)调用该方法的。 - Boyang
4个回答

4
当您调用s1.toString()时,它会查找Super类中定义的toString()方法,因此使用该方法作为子类中可用的超类方法。 您的超类方法toString()正在使用它自己的类变量str(其值在超类中初始化)作为该方法的返回值,因此输出结果为I'm super! 如果您想要获得I'm sub.\n的输出,则需要重复使用与超类相同的变量,并将新的字符串值即I'm sub.\n分配给它。最好的选择是使用构造函数:
  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());
    }
  }

这就是我想知道的。谢谢! - Boyang

2

你在子类中隐藏(shadowing)了str。由于你没有在子类中重写toString(),所以调用是在父类中进行的,并且它看到的是父类的str

如果你这样做:

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

它会输出您期望的内容。

1

此调用正在使用超类:

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

原因是 Sub 没有覆盖 str,它只是声明了另一个变量,恰好具有相同的名称。换句话说,sub 只是隐藏了 Super 中的变量(数据成员不具有多态性)。
如果它们表示不同的含义,您可以为它们命名不同的名称。或者,也可以使用 getter 方法访问(或修改)父属性的 Sub

那么,每当我调用超类中定义的方法时,它会使用超类的字段,而不是子类的字段? - Boyang

1

你没有将字符串常量 "I'm sub.\n" 分配给共享的超类字段,而是创建了一个局部于子类的字段并将其分配给该字段。

例如:

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

如需更多信息,请参见控制类成员的访问


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接