“构造函数调用必须是Java中构造函数中的第一个语句”问题

“Constructor call must be the first statement in a constructor” issue in Java

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Why does this() and super() have to be the first statement in a constructor?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
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) {
        ...
    }
}

但是,我得到一个错误"constructor call must be the first statement in a constructor"错误。

enter image description here

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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约定?调用公共方法是一种好方法吗?


没有什么内在的原因,为什么Java不能被扩展到允许在构造函数之前不访问EDCOX1×4的语句。但是,这会增加语言的复杂性,并在使用时模糊代码(特别是当您认为调用可能是隐式的时候)。

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

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

1
2
3
4
5
6
7
8
9
10
    public IMethodFinder(String projectName, String methodName,
        int numberOfParameters) {
        this(
            JavaCore.create(
                ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)
            ),
            methodName,
            numberOfParameters
        );
    }

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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)。

Historically, this() or super() must be first in a constructor. This
restriction was never popular, and perceived as arbitrary. There were
a number of subtle reasons, including the verification of
invokespecial, that contributed to this restriction. Over the years,
we've addressed these at the VM level, to the point where it becomes
practical to consider lifting this restriction, not just for records,
but for all constructors.


解决方案1:您的构造器应该有一个更好的流程,以避免使用通用的init。通常情况下,一个构造函数会更基本,并构造一个完整的有效对象,然后外部构造函数可以修饰这个对象。

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

解决方案3:与普通的init方法不同,只有静态方法可以为您进行独立的预处理。如myField = processInputField(myField)。普通的init方法在最后一个字段中的作用非常差,这是它们不好实践的一个更强有力的原因——本质上,是的,施工人员应该完成施工的全部工作。


看到你第一个问题的答案对于您的第二个问题-是的,对这些情况使用某种init()方法是相对公认的。


看看这个。它可能有助于理解Java的安全调用。

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