繁体   English   中英

Java不继承访问器方法?

[英]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的成员deedum隐藏了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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM