2

我去“刷新”我的Java,却发现显然我不懂基本概念!这是一个我无法弄清楚的简单问题:

public abstract class Robot {

    private String model = "NONAME";

    public Robot() {
        System.out.println("Making a generic " + model + " robot, type: " + this.getClass());
    }

    public String getModel() {
        return model;
    }
}

好的,子类:

public class Terminator extends Robot {
    private String model;

    public Terminator(String model) {
        super();
        System.out.println("Making a " + model + " terminator, type: " + this.getClass());
        this.model = model;
    }
}

然后我运行一个简单的示例,期望打印“T1000”:

    Robot r1 = new Terminator("T1000");
    System.out.println(r1.getModel());

没有骰子!打印“NONAME”。在此之前,我从构造函数中得到这个输出:

  • 制作一个通用的 NONAME 机器人,输入:class com.akarpov.tutorial.Terminator
  • 制作 T1000 终结器,输入:class com.akarpov.tutorial.Terminator

所以,好吧,我看到 Java 发现了我的类的运行时实例是 Terminator,这是告诉“新”来制作的。而且,显然,终结者实例确实保留了模型 ==“T1000”的副本。但是在调试器(IntelliJ)中检查 r1 对象,我看到两个名为“模型”的变量,位于不同的地址(显然),具有不同的字符串。而且,显然,正如输出所暗示的,抽象类中的 getModel 选择了 Robot 类中定义的默认值,而不是传递给 Terminator 的构造函数(并保留在对象中)的默认值。

关于抽象类和继承,我不了解什么,我将如何获得默认值和默认行为(即 getModel),它在子类中获取特定数据(即“T1000”)?谢谢!如果这已经被多次回答过,我很抱歉——我看了看,但没有任何反应。

4

4 回答 4

2

您的问题在于 private 修饰符...模型变量在两个类中分别存在两次。私有意味着仅对该类可见。您可能想要使用 setter 方法。

于 2013-07-06T17:58:23.340 回答
1

哦,天哪,我发帖后就明白了。我的错误是在终结者中声明了另一个字符串模型,这导致将模型隐藏在机器人中——因此有两个副本。删除它解决了这个问题。啊!

于 2013-07-06T17:58:26.230 回答
1

您遇到的问题是您确实在创建两个变量。现在,使用您的代码,当您调用时,r1.getModel()您将获得原始的基类model

如果您希望能够从子类设置模型,您有几个选择。您可以通过声明一个 new 来实现您开始的方向String model,但是您必须继续覆盖getModel()超类中的方法,以便您的子类将查找它自己的方法model而不是超类model

public class Terminator extends Robot {
    private String model;

    public Terminator(String model) {
        super();
        System.out.println("Making a " + model + " terminator, type: " + this.getClass());
        this.model = model;
    }

    @Override
    public String getModel(){
    return model;
    }
}

另一种选择是在超类中为model.

public abstract class Robot{

    private String model = "NONAME";

    public Robot() {
        System.out.println("Making a generic " + model + " robot, type: " + this.getClass());
    }

    public String getModel() {
        return model;
    }

    protected void setModel(String str){
        this.model = str;
    }
}

然后您只需在调用 Terminator 对象setModel(model)之前调用它getModel(),您将获得所需的输出。

于 2013-07-06T18:24:46.257 回答
0

让我们来看看这行代码

Robot r1 = new Terminator("T1000");

所以这调用了 Terminator(String) 构造函数。构造函数做的第一件事是显式调用超类构造函数。它会自动完成,但是您已经明确地编写了 super() ,这很好。超类构造函数做了一件事:

System.out.println("Making a generic " + model + " robot, type: " + this.getClass());

好的,所以它打印出“制作通用 NONAME 机器人,输入:终结者”,因为这是该方法所看到的。它没有对任何“模型”变量的本地引用,因此它使用在 Robot 类中定义的实例变量。然后将控制权交还给 Terminator 构造函数,该构造函数继续打印输出

System.out.println("Making a " + model + " terminator, type: " + this.getClass());

但是这一次它会按照你的预期工作,因为模型变量是由调用方法的类传递的,所以它会隐藏你的实例变量。因此其值为“T1000”。希望这是有道理的

于 2013-07-06T18:03:04.203 回答