Java抽象类+继承——范围或名称解析



我去"刷新"我的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,这就是"new"被要求制作的。而且,很明显,Terminator实例确实保留了model=="T1000"的副本。但是在调试器(IntelliJ)中检查r1对象时,我看到两个名为"model"的变量,位于不同的地址(显然),具有不同的字符串。而且,很明显,正如输出所示,抽象类中的getModel会获取Robot类中定义的默认值,而不是传递给Terminator的构造函数(并保留在对象内部)的值。

关于抽象类和继承,我不明白什么,我该如何使用默认值and默认行为(即getModel)来获取子类中的特定数据(即"T1000")?谢谢如果这件事以前被重复过很多次,我很抱歉-我看了看,但没有什么东西向我扑来。

您的问题是私有修饰符。。。模型变量在两个类中分别存在两次。Private表示仅对该类可见。您可能需要使用setter方法。

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

若你们想从一个子类中设置模型,你们有几个选项。您可以按照开始时的方向声明一个新的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 of protected setter方法。

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对象调用getModel()之前先调用setModel(model),就可以得到所需的输出。

哦,天哪,我在发布后就收到了。我的错误是在Terminator中声明了另一个String模型,这导致了在Robot中隐藏该模型——因此产生了两个副本。移除它解决了问题。啊!

让我们走过这行代码

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"。希望这是有意义的

最新更新