在构造函数中使用“this”作为方法调用的参数

Using 'this' as a parameter to a method call in a constructor

提问人: 提问时间:9/24/2008 更新时间:9/25/2008 访问量:10240

问:

我有一个构造函数,如下所示:

public Agent(){

    this.name = "John";
    this.id = 9;
    this.setTopWorldAgent(this, "Top_World_Agent", true);

}

我在方法调用中收到一个空指针异常。这似乎是因为我在 setTopWorldAgent 方法中使用“this”作为参数。通过删除此方法调用,一切看起来都很好。为什么会这样?还有其他人经历过吗?

Java 构造函数 方法 调用

评论

0赞 Dave Costa 9/24/2008
我猜setTopWorldAgent中的代码是发生异常的地方。也许您可以添加异常的堆栈跟踪和该方法的代码。
0赞 Lou Franco 9/24/2008
我想看看提问者的最终解决方案是什么。
0赞 Pavel 8/23/2015
这称为参数,而不是参数。

答:

0赞 sblundy 9/24/2008 #1

this不是空的,这一点是肯定的。它已被分配。

也就是说,无需传入方法,它在所有实例方法中都自动可用。如果该方法是静态的,则可能需要将其重构为实例方法。this

8赞 Lou Franco 9/24/2008 #2

你可以把它传递给方法,但setTopWorldAgent()不能是抽象的。不能在构造函数中进行虚拟调用。

在对象的构造函数中,可以调用该对象或基类中定义的方法,但不能指望调用派生类将提供的内容,因为派生类的某些部分尚未构造。如果setTopWorldAgent()是抽象的,我本来会预料到某种编译器错误。

在 Java 中,你可以通过构造函数和派生类获得令人惊讶的行为——下面是一个例子

http://en.wikipedia.org/wiki/Virtual_functions#Java_3

如果您习惯使用 C# 或 C++,您可能会认为调用虚拟函数而不是调用重写的函数是安全的。在 Java 中,即使派生类未完全构造,也会进行虚拟调用。

如果这不是正在发生的事情,那么据推测,setTopWorldAgent() 需要的所有部分都已初始化 - 如果不是,则可能是需要初始化的成员之一。

编辑:以为这是C#

评论

0赞 Konrad Rudolph 9/24/2008
但即使你这样做了,函数调用也不会失败!
0赞 Henry B 9/24/2008
这个答案显然是不正确的。即使该类是抽象的,并且方法 setTopWorldAgent 也是抽象的,此时的创建也会将其视为不为 null。它很容易用测试用例来显示。
0赞 Konrad Rudolph 9/24/2008
该死的,你们为什么要对这个答案投反对票?没错!
0赞 sblundy 9/24/2008
在 Java 中,您可以调用抽象方法,它将被解析为子类中的实现方法。但是您说得对,子类变量不会被初始化。父类构造函数在子类之前调用。
0赞 Lou Franco 9/24/2008
谢谢康拉德!这不是 null -- 其他东西是。我建议的东西可能是无效的,或者你可能会被愚弄,以为某物被调用了,而事实并非如此。
1赞 Khoth 9/24/2008 #3

“this”绝不应为 null。您确定因此而引发异常吗?

需要注意的是,如果方法是虚拟的,或者调用任何虚拟方法,那么在初始化子类的变量之前,可能会运行属于子类的方法。

评论

0赞 sblundy 9/24/2008
在 Java 中,您可以在构造函数中调用抽象方法。将调用子类中的实现方法。
0赞 Konrad Rudolph 9/24/2008 #4

错误一定在其他地方,因为上面的代码肯定有效,空引用必须是其他东西。

2赞 Hank Gay 9/24/2008 #5

为什么需要作为论据?根据调用,它是一个实例方法,因此它可以引用,而无需将其作为参数接收。setTopWorldAgentthisthis

1赞 Henry B 9/24/2008 #6

我想得更切中要害,你到底为什么要将“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();
  }
}
1赞 Paul Manzotti 9/24/2008 #7

鉴于 setTopWorldAgent 似乎是一个实例方法,您为什么要将其传递给它呢?

5赞 Rob 9/24/2008 #8

出于好奇,为什么要将“this”传递给同一类的成员函数?setTopWorldAgent() 可以直接使用 'this'。看起来您的构造函数或 setTopWorldAgent() 不是静态的,所以我不确定为什么要向成员函数传递它已经可以访问的内容。

除非我错过了什么......

0赞 JeeBee 9/24/2008 #9

如果你的代理正在实现ITopWorldAgent,那么你实际上应该这样做:


Agent agent = new Agent("John", 9);
agent.setTopWorldAgent(agent, "Top_World_Agent", true);

如果不是,那你为什么要以你现在的方式设置一些东西?

我假设setTopWorldAgent方法中的某些内容正在使用尚未在构造函数中初始化的值。

0赞 DJClayworth 9/25/2008 #10

Java 的规则规定,你永远不应该将 'this' 从其构造函数传递给另一个方法,原因很简单,该对象尚未完全构造。它引用的对象可能处于不一致的状态。我很惊讶实际的“this”引用是 null,但一点也不惊讶“this”的某些成员在传递给 setTopWorldAgent 时为 null,并且该方法因此抛出异常。

通常,只要您实际上不访问任何成员或调用方法,例如,如果您想在另一个对象中设置对“this”的引用,就可以从构造函数传递“this”。

当然,在这种情况下,参数是不必要的,因为该方法已经引用了“this”。

0赞 Dennis S 9/25/2008 #11

很高兴你得到了答案。我想补充一点,将“this”作为参数传递可能会导致意外的并发问题。基本上,您提供了对象状态被潜在的非线程安全代码不安全地操纵的可能性。