1

我有一个abstract类,AbstractNode和一个扩展它的具体类——节点。

我试图通过声明对象AbstractClass并用 new Node() 实例化它们来“编程到接口”。

当我在构造函数中初始化它们后尝试在 Node 中使用变量时,我得到一个空指针。但是,如果我改用 getter 方法,一切正常。我错过了什么?

public abstract class AbstractNode
{    
    String str;
    public abstract String getStr();
}

public class Node extends AbstractNode
{
    String str;

    public Node()
    {
        str= new String();
    }

    public String getStr()
    {
        return str;
    }
}

主要方法如下所示:

public static void main(String[] args)
{
    AbstractNode n= new Node();
    String nullStr= n.str;
    String regularStr= n.getStr();
}

现在,nullStr包含一个null引用,并且regularStr包含一个对n.str. 这里发生了什么?我可以直接访问其他不需要初始化的原始类型字段,例如 int,而无需任何 getter 方法。

4

4 回答 4

7

您正在“遮蔽”变量strAbstractNode有一个String有名str的,再Node有一个不同的String,也有名的str。的构造函数Node将一个空字符串分配给Node.str,但AbstractNode.str仍然是null因为它从未被分配过。getStr()返回值 inNode.str因为那是str它看到的命名为“最近”的变量。您的代码main正在读取AbstractNode.str,因为编译器在编译时解析其全名,并且变量的声明类型nAbstractNode. 删除 中的重复String strNode

于 2013-08-23T13:29:56.263 回答
2

现在,nullStr 包含一个 Null 引用,而 regularStr 包含一个对 n.str 的引用。这里发生了什么?

您有两个 str变量 - 一个在 中声明AbstractNode,一个在Node.

现在n被声明为AbstractNode,所以:

String nullStr = n.str;

获取在 中声明的变量的值AbstractNode,而这个:

String regularStr= n.getStr();

调用 in 中声明的方法Node,该方法返回 in 中声明的变量Node

你应该吸取的教训:

  • 决定一个对象应该有多少个状态,并且只声明那么多的变量。任何时候,当你在类层次结构中有两个同名的变量时,你至少应该感到不舒服。如果它们真正代表不同的状态,您应该能够找到不同的名称。
  • 如果您只有私有字段,则阴影变得几乎无关紧要,因为您无论如何无法直接访问这些字段。

我建议修复声明strin AbstractNode,理想情况下使其成为最终的,并创建一个protected接受它的值的构造函数。您可能也希望有一个访问器AbstractNode,尽管目前还不清楚。str也不是变量的描述性名称 - 它是节点的值吗?节点名称?谁知道。我的课程是这样的:

public abstract class AbstractNode {
    private final String name;

    protected AbstractNode(String name) {
        this.name = name;
    }

    public abstract String getName() {
        return name;
    }

    // Presumably some abstract methods?
}

public final class Node extends AbstractNode {
    public Node() {
        super("Some default name");
    }
}
于 2013-08-23T13:31:59.613 回答
1

问题是虽然方法是可覆盖的,但字段不是。

因为您将变量的类型声明为AbstractNode,所以表达式n.str引用 中的字段AbstractNode,即使实际类型是Node。这是因为字段在编译时静态绑定到类型。

另一方面,方法是在运行时解析的,这就是您可以覆盖它们的原因:表达式n.getStr()是根据对象的实际类型解析的。

于 2013-08-23T13:34:22.390 回答
0
public String getStr()
{
    return str;
}

and

String regularStr= n.getStr();

This function is overriden and at runtime the corresponding function in Node class is selected and hence you get appropriate results.

But when you say

String nullStr= n.str;

n variable from AbstractNode class is fetched(which is null).Note that Variables are read only and cannot be overriden,

于 2013-08-23T13:36:10.643 回答