8

重複の可能性:
this() と super() をコンストラクターの最初のステートメントにする必要があるのはなぜですか?

Java でコンストラクター チェーンが必要です。たとえば、最初のコンストラクターではパラメーターとして文字列を使用し、パラメーター文字列からオブジェクトを作成するときに 2 番目のコンストラクターを呼び出します。

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) {
        ... 
    }
}

しかし、「コンストラクター呼び出しはコンストラクターの最初のステートメントでなければなりません」というエラーが発生しました。

ここに画像の説明を入力

2 つのコンストラクター間で共有される共通のコードを作成しましたが、これが問題を回避する唯一の解決策かどうかはわかりません。

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

thisコンストラクターの前にアクセスしないステートメントを許可するように Java を拡張できなかった本質的な理由はありません。ただし、これは言語の複雑さを増し、使用するとコードがわかりにくくなります (特に、呼び出しが暗黙的である可能性があると考える場合)。

一般に、コンストラクターはできるだけ単純に保ちたいと考えています。init()メソッドは、の使用を妨げるため、悪い考えですfinal。コードが変更可能な static にアクセスしているように見えますが、これは本当に悪い考えです。

特定のコードについては、次のように記述できます。

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

より一般的なハックは、コンストラクターへの呼び出し内で静的メソッドを呼び出すことです。

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 月の編集:メッセージRecords: construction and validation Oracle は、この制限を削除することを提案しています (ただし、C# とは異なり、コンストラクター チェーンの前this確実に未割り当て(DU) になります)。

歴史的に、 this() または super() はコンストラクターの最初になければなりません。この制限は一般的ではなく、恣意的であると認識されていました。この制限の原因となったのは、invokespecial の検証など、いくつかの微妙な理由がありました。何年にもわたって、VM レベルでこれらの問題に対処してきましたが、レコードだけでなく、すべてのコンストラクターに対して、この制限を解除することを検討することが現実的になりました。

于 2012-12-28T16:35:16.803 に答える
2

解決策 1: コンストラクターは、一般的なinit. 多くの場合、1 つのコンストラクターがより基本的になり、完全な有効なオブジェクトを構築し、外側のコンストラクターがこれを装飾できます。

解決策 2: 多くの場合、ここで必要な前処理を処理できる静的ファクトリ メソッドを使用することをお勧めします。これは、このパターンの適切な使用例のように見えます。

解決策 3: 一般的なメソッドの代わりにinit、分離された前処理を行う静的メソッドを使用します。例えばmyField = processInputField(myField)。一般的なinitメソッドは、最終的なフィールドで非常にうまく機能しません。これは、それらが悪い習慣であるというより強力な理由です。基本的に、はい、コンストラクターは構築の完全な作業を行う必要があります。

于 2012-12-28T16:30:20.203 に答える
1

2番目の質問と同様に、最初の質問に対するこの回答を参照してください-はい、これらの場合にある種の init() メソッドを使用することは比較的受け入れられています

于 2012-12-28T16:31:54.490 に答える
0

これを見てください。Javaコンストラクター呼び出しについて理解するのに役立つかもしれません。

コンストラクター呼び出しは、コンストラクターの最初のステートメントでなければなりません

于 2012-12-28T16:33:57.683 に答える