8

可能重复:
为什么 this() 和 super() 必须是构造函数中的第一个语句?

我想在 Java 中有构造函数链。例如,对于第一个构造函数,我有一个字符串作为参数,并在我从参数字符串创建对象时调用第二个构造函数。

public class IMethodFinder {
    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        this(javaProject, methodName, numberOfParameters);
    }

    public IMethodFinder(IJavaProject javaProject, String methodName,
        int numberOfParameters) {
        ... 
    }
}

但是,我收到错误“构造函数调用必须是构造函数中的第一条语句”错误。

在此处输入图像描述

我制作了一个在两个构造函数之间共享的通用代码,但我不确定这是绕过该问题的唯一解决方案。

public class IMethodFinder {
    public IMethodFinder(IJavaProject javaProject, String methodName,
            int numberOfParameters) {
        dosomething(javaProject, methodName, numberOfParameters);
    }

    public IMethodFinder(String projectName, String methodName,
            int numberOfParameters) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        dosomething(javaProject, methodName, numberOfParameters);
    }

    private void dosomething(IJavaProject javaProject, String methodName,
            int numberOfParameters)
    {
       ...  
    }

}
  • 为什么 Java 需要构造函数调用作为第一条语句?这个要求背后的想法是什么?
  • 对于我的情况,Java 的约定是什么?调用通用方法是一个好方法吗?
4

4 回答 4

15

没有内在的原因可以扩展 Java 以允许this在构造函数之前不访问的语句。但是,这会增加语言的复杂性并在使用时混淆代码(特别是当您认为调用可能是隐式的时)。

通常,您希望使构造函数尽可能简单。init()方法是一个坏主意,因为它们会阻止使用final. 似乎代码正在访问一个可变静态,这是一个非常糟糕的主意。

对于您的特定代码,您可以编写:

    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        this(
            JavaCore.create(
                ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)
            ),
            methodName,
            numberOfParameters
        );
    }

更一般的 hack 是在对构造函数的调用中调用静态方法:

public class IMethodFinder {
    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        this(createProject(projectName), methodName, numberOfParameters);
    }

    public IMethodFinder(IJavaProject javaProject, String methodName,
        int numberOfParameters) {
        ... 
    }

    private static IJavaProject createProject(String projectName) {
        IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName);
        IJavaProject javaProject = JavaCore.create(project);
        return javaProject;
    }
}

2018 年 3 月编辑:在消息记录中:构造和验证Oracle 建议删除此限制(但与 C# 不同,在构造函数链接之前肯定this会取消分配(DU))。

从历史上看,this() 或 super() 必须在构造函数中排在第一位。这种限制从未流行过,并且被认为是任意的。有许多微妙的原因,包括对 invokespecial 的验证,导致了这种限制。多年来,我们已经在 VM 级别解决了这些问题,以至于考虑解除这个限制变得切实可行,不仅是为了记录,而是为了所有构造函数。

于 2012-12-28T16:35:16.803 回答
2

解决方案 1:您的构造函数应该有一个更明确的流程,以避免使用常见的init. 很多时候,一个构造函数会更基本并构造一个完整的有效对象,然后外部构造函数可以装饰它。

解决方案 2:使用静态工厂方法通常是一种很好的做法,例如可以在此处处理您需要的预处理。这看起来是这种模式的一个很好的用例。

解决方案 3:而不是通用init方法,只需使用静态方法为您进行隔离预处理。例如myField = processInputField(myField)。通用init方法在 final 字段上的表现很差,这是它们是不好的做法的一个更有力的原因 - 本质上,是的,构造函数应该完成构造的全部工作。

于 2012-12-28T16:30:20.203 回答
1

看到你的第一个问题和你的第二个问题的答案- 是的,在这些情况下使用某种 init() 方法是相对可接受的

于 2012-12-28T16:31:54.490 回答
0

看看这个。它可能有助于理解 java 构造函数调用。

构造函数调用必须是构造函数中的第一条语句

于 2012-12-28T16:33:57.683 回答