简体   繁体   English

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

[英]Java abstract class + inheritance — scope or name resolution

I went to 'refresh' my Java, only to realize that apparently I don't understand basic concepts! 我去“刷新”我的Java,只是意识到显然我不了解基本概念! Here's a simple one I can't figure out: 这是我不知道的简单方法:

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;
    }
}

OK, and the subclass: OK,然后是子类:

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;
    }
}

And then I run a simple example, expecting "T1000" to be printed: 然后运行一个简单的示例,期望打印“ T1000”:

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

No dice! 没有骰子! "NONAME" is printed. 打印“ NONAME”。 Before that, I get this output from constructors: 在此之前,我从构造函数获得以下输出:

  • Making a generic NONAME robot, type: class com.akarpov.tutorial.Terminator 制作一个通用的NONAME机器人,键入:class com.akarpov.tutorial.Terminator
  • Making a T1000 terminator, type: class com.akarpov.tutorial.Terminator 制作T1000终结器,键入:类com.akarpov.tutorial.Terminator

So, OK, I see that Java picks up the fact that runtime instance of my class is Terminator, which is what 'new' is told to make. 好了,我看到Java意识到我的类的运行时实例是Terminator,这就是“ new”的意思。 And, obviously, the Terminator instance does keep the copy of the model == "T1000". 而且,显然,终结者实例的确保留了模型的副本==“ T1000”。 But inspecting the r1 object in a debugger (IntelliJ) I see two variables named 'model', at different addresses (obviously), with different strings. 但是在调试器(IntelliJ)中检查r1对象时,我看到两个名为'model'的变量,它们位于不同的地址(显然),具有不同的字符串。 And, obviously, as the output suggests, the getModel in the abstract class picks up the default value defined in the Robot class, not the one passed to the Terminator's constructor (and retained inside the object). 而且,显然,如输出所示,抽象类中的getModel选取了Robot类中定义的默认值,而不是传递给Terminator的构造函数(并保留在对象内部)的默认值。

What is it I don't understand about abstract classes and inheritance, and how would I go about having a default value AND default behavior (ie getModel), which picks up the specific data (ie "T1000") in a subclass? 关于抽象类和继承,我不了解什么?如何使用默认值和默认行为(即getModel)来选择子类中的特定数据(即“ T1000”)? Thanks! 谢谢! And my apologies if this has been aswered many times before - I looked but nothing jumped at me. 我很抱歉,如果这已经被很多次困扰了-我看了一下,但是什么都没跳。

Your issue is with the private modifier... The model variable exists twice separately in the two classes. 您的问题与private修饰符有关……模型变量在两个类中分别存在两次。 Private means only visible to that class. 私有意味着仅对该类可见。 You may want to use a setter method. 您可能要使用setter方法。

Oh gosh I got it right after posting. 哦,天哪发布我就知道了。 My mistake was in declaring another String model in the Terminator, which led to hiding the model in Robot -- hence the two copies. 我的错误是在终结者中声明了另一个String模型,这导致将模型隐藏在Robot中-因此产生了两个副本。 Removing it solved the problem. 删除它解决了问题。 Argh! 哎呀!

The issue you are having is that you are indeed creating two variables. 您遇到的问题是您确实在创建两个变量。 Now, with the code you have in place, when you call r1.getModel() you will get the original base class model . 现在,有了代码,调用r1.getModel()您将获得原始的基类model

If you want to be able to set model from a subclass you have a few options. 如果您希望能够从子类中设置模型,则有几种选择。 You can go the direction that you started by declaring a new String model , but you must then go on to override the getModel() method from the superclass so that your subclass will look to its own model instead of the superclass 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;
    }
}

Another option would be to create a public of protected setter method in the superclass for model . 另一种选择是在model的超类中创建一个受保护的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;
    }
}

And then you would just have your Terminator object call setModel(model) before it called getModel() and you would have the desired output. 然后,只需将Terminator对象调用setModel(model)然后再调用getModel()然后将获得所需的输出。

Let's walk through this line of code 让我们看一下这段代码

Robot r1 = new Terminator("T1000");

So this calls the Terminator(String) constructor. 因此,这将调用Terminator(String)构造函数。 The first thing the constructor does is call the superclass constructor explicitly. 构造函数要做的第一件事是显式调用超类构造函数。 It would have done it automatically, but you've written super() explicitly and that's fine. 它会自动完成,但是您已经显式地编写了super(),这很好。 The superclass constructor does 1 thing: 超类构造函数执行1件事:

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

Ok, so it prints out "Making a generic NONAME robot, type: Terminator" because that is what the method sees. 好的,因此它会打印出“制作一个通用的NONAME机器人,键入:Terminator”,因为这是该方法的结果。 It has no local reference to any "model" variable, so it uses the instance variable defined within the Robot class. 它没有任何“模型”变量的本地引用,因此它使用Robot类中定义的实例变量。 Then control is given back to the Terminator constructor, which proceeds to print out 然后将控制权交还给Terminator构造函数,后者继续打印输出

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

But this time it works how you expect because the model variable was passed by the class calling the method, so it shadows your instance variable. 但是这一次它可以按您期望的那样工作,因为模型变量是由调用该方法的类传递的,因此它遮蔽了您的实例变量。 Therefore its value is "T1000". 因此,其值为“ T1000”。 Hopefully that makes sense 希望这是有道理的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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