调用super()必须是构造函数体中的第一条语句。

9

我正在编写一个名为LoginRequest的构造函数,它继承了一个叫做JsobObjectRequest的类(来自于Android中的Volley框架,但这与问题完全无关)

使用以下代码:

 public LoginRequest(String username, String password, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener) {
        Boolean hasCredentials=(username!=null && password!=null);
        int method=hasCredentials? Method.POST:Request.Method.GET;
        super(method, API_URL_LOGIN, null, responseListener, errorListener);

        this.username=username;
        this.password=password;

    }

我遇到了一个错误:在构造函数主体中,调用super()必须是第一条语句。
相反,这段代码编译得很好:
 public LoginRequest(String username, String password, Response.Listener<JSONObject> responseListener, Response.ErrorListener errorListener) {
        super((username!=null && password!=null)? Method.POST:Request.Method.GET, API_URL_LOGIN, null, responseListener, errorListener);

        this.username=username;
        this.password=password;

    }

但这不是完全一样的事情吗?在两种情况下,在调用超类构造函数之前,都会进行几个微不足道的计算,这些计算是基于传递给子类构造函数的参数值的。既然编译器可以编译第二个示例,为什么不能编译第一个示例呢?
调用super构造函数必须是第一条语句的规范是否比它需要的简单化,还是我错过了什么东西?
编辑:这被错误地标记为为什么this()和super()必须是构造函数中的第一条语句?那个问题更加通用,并问为什么super()必须是第一条语句。这个问题是为什么像我发布的这种情况会破坏这些要求(并且这个问题已经得到满意的答复)。

1
它可能与编译器有关吗?另一个编译器可能会理解您的代码并将其视为可以接受的... - kiwixz
2
它不依赖于编译器。这在JLS中已经说明了。 - kraskevich
1
“它是否比必要的更简单?” 可能是这样,但为了确保安全地完成任务而设计语言并不容易。Swift是今年刚发布的一种编程语言,它尝试了一组更复杂的规则,但我还不知道它到底好坏如何,或者它是否会在您的特定情况下有所帮助。 - ajb
1
希望你的“太懒了”评论是开玩笑的。问题不在于编译器是否太懒。为了拥有一种语言标准,必须非常准确地规定在super()之前允许什么和不允许什么(否则我们可能会有一些代码被一个编译器接受而被另一个编译器拒绝)。这并不容易。也许可以稍微放宽限制,允许一些不调用任何方法的赋值语句,例如。但进行“彻底”的检查可能是不可行的。 - ajb
是的,这与编译器无关,而是规范的问题。我的“懒惰”意味着它强制执行的条件比实际必要的条件更加严格,因为这样检查起来更容易。这并不是批评它(也许没有其他更好的方式),我只是想知道是否情况确实如此,或者是否有更具体的原因。 - matteo
1个回答

13

Java 强制要求在构造函数中调用 super(无论显式还是隐式)必须是第一个语句。这是为了避免子类部分被初始化而父类部分尚未初始化。

在您的情况下,您只进行本地的“琐碎计算”,所以一切都考虑周全,这没有问题。然而,Java 编译器并不会确定在调用 super 之前是否实际进行任何初始化。它只是禁止在 super() 之前执行所有语句。


4
我明白了,谢谢。令人惊奇的是,一个编译器可以负责检测到无法到达的代码,却不能够检查构造函数中的代码是否可以执行实际的初始化操作。 - matteo
2
它可以检查这样的事情。然而,也许在编译过程中需要太多时间(猜测)。 - rgettman
什么是对象的子类部分? - Rico
所以如果super不是第一行,那么你可以覆盖超类方法,并且当调用super时它会被重写?o.O - Rico
哦,等等。我在其他地方找到了它的含义。为了避免引用超类中尚未创建的实体。O.o - Rico
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接