[英]Java not inheriting accessor methods?
给定一个扩展了实现接口“ DeeDum”的类“ Foo”的类“ Bar”
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为什么不能继承访问器(为什么它们选择了这种奇怪的选择?)
还是我做错了什么?
实际上,我仍然看到一些奇怪且不确定的东西。 如果您还有另一个扩展Foo的类“ Bar”,并在初始化块中设置继承的访问器
虽然可以在上面的块中设置parent属性,但实际上并没有为子类创建副本。
对于多个类,这似乎是非确定性的初始化。
因此,如果您有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,但是为什么声明有所不同? 在我看来“未定义”。
问题是您在Bar
重复声明Foo
的成员dee
和dum
隐藏了Foo
。 Bar
有自己的成员; Bar
永远不会使用Foo
那些。 你的意思是像
public class Bar extends Foo {
{
dee = "DEE";
dum = "DUM";
}
}
您将用子类中定义的变量隐藏继承的变量。
public class Bar extends Foo {
public Bar() {
dee = "DEE";
dum = "DUM";
}
}
应该更好地工作。
当调用mybar.getDee()
,您正在调用Foo
基类中定义的方法。 (该方法是 Bar
继承的。否则,首先不允许您在Bar
实例变量上调用它。)该方法返回dee
字段的值,但它是Foo
定义的dee
字段。 class —定义方法本身的类。 编译器在Foo
类中解析了方法编译时对该字段的引用。
其他一些答案使用覆盖(override)一词通过在Bar
声明一个名为dee
的字段来定义您所做的事情,但是事实并非如此。 您不能覆盖字段,因为字段不是虚拟的。 不过,也许您认为它们是。 如果存在“虚拟字段”之类的东西,我也可能希望getDee()
返回该字段的运行时类版本( Bar
的版本),而不是该方法时在范围内的版本。被编译( Foo
的)。 但这根本不是Java(或C#,C ++,Delphi或我所知道的任何其他语言)的工作方式。 您习惯用哪种语言工作?
访问器方法本身(例如getDee()
)是继承的,而实例变量则不是。
如果实例变量可以在子类中被覆盖(如您在此处尝试执行的操作),则将导致比解决的问题更多的问题。
访问器不是问题,这是领域。 访问器引用的是Foo.this.dee
,而不是单独的Bar.this.dee
。
至于第二个“问题” ...
实际上,我仍然看到一些奇怪且不确定的东西...
...
“ ... System.out.println(baz.getDee()); //'DEE'但会期望'dee'”
如果在发布问题以查看实际结果之前运行程序,这将很有用。
这就是我得到的。 如您所料,它是“迪”。
您可以通过创建文件,编译并运行它们来亲自查看它,如下所示:
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?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.