我有一个如下构造函数:
public Agent(){
this.name = "John";
this.id = 9;
this.setTopWorldAgent(this, "Top_World_Agent", true);
}
我在方法调用中得到了一个空指针异常。这似乎是因为我在 setTopWorldAgent 方法中使用“this”作为参数。通过删除此方法调用,一切看起来都很好。为什么会这样?有没有其他人经历过这个?
我有一个如下构造函数:
public Agent(){
this.name = "John";
this.id = 9;
this.setTopWorldAgent(this, "Top_World_Agent", true);
}
我在方法调用中得到了一个空指针异常。这似乎是因为我在 setTopWorldAgent 方法中使用“this”作为参数。通过删除此方法调用,一切看起来都很好。为什么会这样?有没有其他人经历过这个?
您可以将其传递给方法,但 setTopWorldAgent() 不能是抽象的。您不能在构造函数中进行虚拟调用。
在对象的构造函数中,您可以调用在该对象或基类中定义的方法,但不能期望调用将由派生类提供的东西,因为部分派生类尚未构造。如果 setTopWorldAgent() 是抽象的,我会预料到某种编译器错误。
在 Java 中,您可以使用构造函数和派生类获得令人惊讶的行为——这是一个示例
http://en.wikipedia.org/wiki/Virtual_functions#Java_3
如果您习惯于 C# 或 C++,您可能会认为调用虚函数而不是调用被覆盖的函数是安全的。在 Java 中,即使派生类没有完全构造,也会进行虚拟调用。
如果这不是正在发生的事情,那么大概是 setTopWorldAgent() 需要的 this 的所有部分都已初始化——如果不是,它可能是需要初始化的 this 的成员之一。
编辑:认为这是 C#
出于好奇,您为什么将“this”传递给同一类的成员函数?setTopWorldAgent() 可以直接使用 'this'。它看起来不像你的构造函数或 setTopWorldAgent() 是静态的,所以我不确定你为什么要传递一个它已经可以访问的成员函数。
除非我错过了什么...
为什么setTopWorldAgent
需要this
作为论据?基于调用,它是一个实例方法,因此它可以引用this
而不需要将其作为参数接收。
我认为更重要的是,你到底为什么将“this”作为参数传递给“this”中的方法?
以下将测试您所说的发生在您身上的事情,我对此没有任何问题。
public class Test {
public Test() {
this.hi(this);
}
public void hi(Test t) {
System.out.println(t);
}
public static void main(String[] args) throws Exception {
Test t = new Test();
}
}
鉴于 setTopWorldAgent 似乎是一个实例方法,你为什么还要通过它呢?
this
不为空,这是肯定的。已经分配了
也就是说,不需要传入this
方法,它在所有实例方法中自动可用。如果方法是静态的,您可能希望将其重构为实例方法。
“this”永远不应该为空。您确定因此引发了异常吗?
需要注意的是,如果方法是虚拟的,或者调用任何虚拟方法,则属于子类的方法可能会在子类的变量初始化之前运行。
错误必须在其他地方,因为上面的代码肯定有效,空引用必须是其他地方。
如果您的代理正在实施 ITopWorldAgent 那么您实际上应该这样做:
Agent agent = new Agent("John", 9);
agent.setTopWorldAgent(agent, "Top_World_Agent", true);
如果不是,那你为什么要以你现在的方式设置一些东西?
我认为 setTopWorldAgent 方法中的某些内容正在使用尚未在构造函数中初始化的值。
Java 的规则规定你永远不应该将“this”从它的构造函数传递给另一个方法,原因很简单,对象还没有完全构造。它引用的对象可能处于不一致的状态。我很惊讶实际的“this”引用为空,但一点也不惊讶“this”的某些成员在传递给 setTopWorldAgent 时为空,并且该方法因此引发异常。
通常,只要您实际上不访问任何成员或调用方法,例如如果您想在另一个对象中设置对“this”的引用,您就可以从构造函数中传递“this”。
在这种情况下,参数当然是不必要的,因为该方法已经引用了“this”。
很高兴你得到了答案。我想补充一点,将“this”作为参数传递可能会导致意外的并发问题。您基本上提供了对象状态被潜在的非线程安全代码不安全地操作的可能性。