Java不继承访问器方法?

Java不继承访问器方法?,java,inheritance,Java,Inheritance,给定一个扩展类Foo(实现接口DeeDum)的类栏 public interface DeeDum { public String getDee(); public String getDum(); } public class Foo implements DeeDum { public String dee = "D"; public String dum; public String getDee() { return dee; } pu

给定一个扩展类Foo(实现接口DeeDum)的类栏

public interface DeeDum {
    public String getDee();
    public String getDum();
}

public class Foo implements DeeDum {
    public String dee = "D";
    public String dum;

    public String getDee() { return dee; }
    public String getDum() { return dum; }
}

public class Bar extends Foo {
    public String dee = "DEE";
    public String dum = "DUM";
}
为什么这样不行

public static Bar mybar = new Bar();
Assert.assertEquals("DEE", mybar.getDee());
Assert.assertEquals("DUM", mybar.getDum());
我得到的是D和null。换句话说,Bar不会从Foo继承访问器,也不能重写属性。调用mybar.getDum调用类Foo的静态实例,并从父类返回静态属性。即使属性在子类中被重写!这是否意味着您不能继承任何方法或属性

我不能把我的头绕在它周围。为什么Java不能继承访问器,为什么他们选择了这样一个奇怪的选择

还是我只是做错了什么

事实上,我看到了一些奇怪的和不确定的东西。如果您有另一个类“Bar”,它扩展了Foo并在初始化块中设置继承的访问器

虽然您可以在上面的块中设置父属性,但它实际上并不为子类创建副本

对于多个类来说,这似乎是一个不确定的初始化

因此,如果您有Bar和Baz,它们都扩展了foo,并且有一个初始化块,那么看起来它们都继承了Bar设置的值

public class Bar extends Foo {
    {
        dee = "dee";
        dum = "dum";
    }
}
public class Baz extends Foo {
    {
        dee = "DEE";
        dum = "DUM";
    }
}

public static Bar bar = new Bar();
public static Baz baz = new Baz();

System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum());  // DEEDUM
System.out.println("mybar: " + mybar.getDee() + mybar.getDum());  // DEEDUM
但如果它们以不同的顺序实例化,我会得到:

public static Baz baz = new Baz();
public static Bar bar = new Bar();

System.out.println("mybaz: " + mybaz.getDee() + mybaz.getDum());  // deedum
System.out.println("mybar: " + mybar.getDee() + mybar.getDum());  // deedum
如果在基类Foo中设置了默认值,结果仍然不同


我想我现在明白了,Bar和Baz中的初始化块实际上是在设置Foo::dee和Foo::dum,但是为什么声明中会有差异呢?对我来说似乎没有定义。

访问器方法本身(例如getDee)是继承的,但实例变量不是


如果实例变量可以像您在这里尝试的那样在子类中被重写,那么它将导致比修复的问题更多的问题。

您正在用子类中定义的变量隐藏继承的变量

public class Bar extends Foo {
    public Bar() {
        dee = "DEE";
        dum = "DUM";
    }
}

应该会更好。

问题是,你在酒吧里重复声明的Foo成员dee和dum隐藏了Foo的成员dee和dum。大律师公会有自己的会员;这些富将永远不会被酒吧使用。你的意思是

public class Bar extends Foo {
  {
    dee = "DEE";
    dum = "DUM";
  }
}

访问器不是问题,问题在于字段。访问器指的是Foo.this.dee,而不是单独的Bar.this.dee

调用mybar.getDee时,调用的是在Foo基类中定义的方法。该方法由Bar继承。否则,一开始就不允许对Bar实例变量调用它。该方法返回dee字段的值,但它是在Foo类中定义的dee字段,该类定义了方法本身。编译器在编译方法时在Foo类中解析对字段的引用


其他一些答案使用了override这个词来定义您在Bar中声明了一个名为dee的字段,但事实并非如此。无法重写字段,因为字段不是虚拟字段。也许你认为他们是。如果存在虚拟字段,我也可能希望getDee返回运行时类的字段版本,即Bar中的版本,而不是编译方法Foo时在作用域中的版本。但这不是java或C++、或C++、Delphi或任何其他我知道的语言的工作方式。你习惯用什么语言来表达这个问题呢?

至于你的第二个问题

事实上,我看到了一些奇怪的和不确定的东西

…System.out.printlnbaz.getDee;/'“迪”,但会期待“迪”

如果您在发布问题之前运行程序以查看实际结果,这将非常有用

这就是我得到的。正如你所预料的那样

通过创建文件、编译文件并按如下所示运行它们,您可以自己查看它:

C:\oreyes\samples\java\dee>type DeeDum.java Foo.java Bar.java Baz.java Test.java

DeeDum.java


public interface DeeDum {
    public String getDee();
    public String getDum();
}

Foo.java


public class Foo implements DeeDum {
    public String dee = "D";
    public String dum;

    public String getDee() { return dee; }
    public String getDum() { return dum; }
}

Bar.java


public class Bar extends Foo {
    {
        dee = "DEE";
        dum = "DUM";
    }
}

Baz.java


public class Baz extends Foo {
    {
        dee = "dee";
        dum = "dum";
    }
}


Test.java


class Test {
    public static Bar bar = new Bar();
    public static Baz baz = new Baz();
    public static void main( String [] args ) {
        System.out.println(bar.getDee()); // 'DEE'
        System.out.println(baz.getDee()); // 'DEE' but would expect 'dee'
    }
}

C:\oreyes\samples\java\dee>javac *.java

C:\oreyes\samples\java\dee>java Test
DEE
dee

C:\oreyes\samples\java\dee>

PEBKAC?

于是喂食狂潮开始了……这又是一个经典案例:“我不知道X到底是如何工作的,所以X肯定是完全错误的。”Java学校不教Java。11点录音,这就是我想弄明白的。它会引起什么问题?静态变量呢?嗯,我突然想到我要给出的答案介于你不应该这样做和你为什么要这样做之间?所以请原谅我去寻找推荐人恰恰相反。他的问题是他没有覆盖它们——他隐藏了它们。是的,坏例子。我试着给Eclipse编译器编写一个简单的示例——去掉槽中的所有图标,并假设它是正确的。下一个技巧是,我将写一篇关于为什么Unicorns在MS Word中比Griffons更酷的文章来学习西班牙语,并让clippy纠正我的拼写和语法。