我有一个abstract
类,AbstractNode
,以及一个扩展它的具体类 - Node。
我正在尝试"编程到界面"通过声明AbstractClass
的对象并使用新的Node()实例化它们。
当我在构造函数中初始化它们后尝试在Node中使用变量时,我得到一个Null指针。但是,如果我使用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方法。
答案 0 :(得分:7)
你正在“隐藏”变量str
。 AbstractNode
有一个名为String
的{{1}},然后str
有一个不同的Node
,也称为String
。 str
的构造函数将空字符串分配给Node
,但Node.str
仍为AbstractNode.str
,因为它从未被分配过。 null
会返回getStr()
中的值,因为它是它看到的名为Node.str
的“最近”变量。您在str
中的代码正在读取main
,因为编译器在编译时解析其全名,并且变量AbstractNode.str
的声明类型为n
。删除AbstractNode
中的重复String str
。
答案 1 :(得分:2)
现在,nullStr包含一个Null引用,而regularStr包含对n.str的引用。这里发生了什么?
您有两个 str
个变量 - 一个在AbstractNode
中声明,另一个在Node
中声明。
现在n
被声明为AbstractNode
,所以:
String nullStr = n.str;
获取AbstractNode
中声明的变量的值,而不是:
String regularStr= n.getStr();
调用Node
中声明的方法,该方法返回Node
中声明的变量。
你应该学习的课程:
我建议修复仅在str
中声明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");
}
}
答案 2 :(得分:1)
问题在于,当方法可以覆盖时,字段不是。
因为您将变量的类型声明为AbstractNode
,所以表达式n.str
引用AbstractNode
中的字段,即使实际类型为Node
。这是因为字段在编译时静态绑定到类型。
另一方面,方法在运行时被解析,这就是你可以覆盖它们的原因:表达式n.getStr()
是根据对象的实际类型解析的。
答案 3 :(得分:0)
public String getStr()
{
return str;
}
和
String regularStr= n.getStr();
此函数被覆盖,并且在运行时选择了Node类中的相应函数,因此您可以获得适当的结果。
但是当你说
时String nullStr= n.str;
提取了来自AbstractNode类的变量(它为null)。注意变量是只读的,不能被覆盖,