【问题标题】:Is there a way to access the concrete class variable values from concrete methods of an abstract class有没有办法从抽象类的具体方法访问具体的类变量值
【发布时间】:2019-04-10 06:29:27
【问题描述】:

我对Java中的variable hiding and method overridingvirtual method calling有所了解。 我的问题是,为什么变量隐藏在继承方法中不起作用?这是否意味着我们必须重写在每个子类中访问这些变量的方法?

抽象类

public abstract class ClassA{

    protected int i = 0;

    public void printOurStuff(){
        System.out.println(i);
    }

    public void printMyStuff(){
        System.out.println(this.i);
    }

    public void printSomeStuff(String s){
        System.out.println(s);
    }

}

具体类

 public class ClassB extends ClassA{

     protected int i = 1;

     public static main(String[] args){
         ClassB b = new ClassB();
         b.printOurStuff();
         b.printMyStuff();
         b.printSomeStuff(b.i);
     }

 }

结果

0 0 1

EDIT - 将字段的访问修饰符从私有更改为受保护并添加方法printOurStuff

【问题讨论】:

  • 不清楚您要更改哪个结果 - 调用printMyStuff 的结果或调用printSomeStuff(b.i) 的结果。但这是两个完全独立的变量,每个变量只能被同一个类声明中的代码访问,因为它们都是私有变量。
  • 没有。这意味着您应该避免隐藏字段。如果i 需要在子类中可用,请将其设置为受保护的,或者添加可以在子类中调用的受保护的 getter 方法。
  • @JBNizet 更改访问修饰符并不能解决此问题。但是,我要求解释为什么会发生这种情况,而不是如何做到这一点
  • 如果您停止隐藏字段,即如果您删除 ClassB 中的 i 字段并因此有一个 ifield,则会这样做。
  • 更新了问题以反映我感兴趣的问题。

标签: java inheritance abstract-class


【解决方案1】:

当你声明像

这样的私有字段时
  private int i = 0;

这意味着只有这个具体的类可以访问这个变量。该字段对子类不可用。如果您希望该字段可用于子类,则应改为 protected

  protected int i = 0;

要覆盖该字段的值,您可以使用静态块 f.e.:

public class ClassB extends ClassA {
    {
         i = 1;
    }
}

或者在构造函数中赋值:

public class ClassB extends ClassA {
     public ClassB() {
         i = 1;
     }
}

对于您的示例,如果您使用调试器检查 ClassB 对象,您会发现您实际上有两个 i 字段:一个用于 ClassA,一个用于 ClassB

更新:

至于i变量为protected的情况:
仔细查看您的类定义。
您不能不同意您 声明 i 字段两次:ClassAClassB。 JVM 将尊重此声明并遵循您的指示。如果该字段是protected 甚至public,您仍然有两个字段。您不能像覆盖方法一样覆盖它们。当访问像i = ... 这样的字段时,您实际上是在访问最接近您的范围的字段。对于ClassB,它是它的字段i,而不是它的超类ClassA 的字段。

此外,您仍然可以按如下方式访问超类的字段:

super.i = ...

super 是对超类的引用。

【讨论】:

  • 将访问修饰符设置为私有是我在发布问题时犯的一个错误。虽然添加一个静态块并在构造函数中分配变量作为解决此问题的方法是完全可以接受的,但我更关心知道为什么会发生这种情况。是不是因为抽象类中具体方法的范围仅限于抽象类?
  • @KusalHettiarachchi 没有。这是因为字段不是多态的。它们不能被覆盖。只有方法可以被覆盖。因此,如果一个变量(此处为this)的类型为ClassA,并且您访问该变量的字段i,那么编译器会将其静态解析为ClassA.i
  • @KusalHettiarachchi,在答案中提供了一些解释。
  • @JBNizet 我对 b.i 被解析为 1 的值没有任何问题。我想知道为什么方法 printOurStuff 将 i 的值评估为 ClassA 中设置的值
  • @KusalHettiarachchi,如果您没有名称冲突,您实际上不必在构造函数或静态块中初始化它。这只是范围问题:两个具有相同名称的变量,因此编译器会根据范围选择最接近的一个。
猜你喜欢
  • 2018-05-12
  • 2011-04-12
  • 2013-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多