Java - 非静的メソッドは静的コンテキストから参照できません

開発してみると、以下のように non-static method cannot be referenced from a static context コンパイルエラーが発生することがあります。

error: non-static method printUserName() cannot be referenced from a static context
        printUserName();
        ^

1. エラー発生原因

Static メソッドはオブジェクトを生成せずに使用できるため、Static メソッドの内部ではメンバー変数やメソッドを使用できません。 static メソッドの呼び出し時にオブジェクトが作成されなかった可能性があるため、オブジェクトの変数とメソッドへのアクセスを許可しません。また、オブジェクトが作成されていても、Staticメソッドでどのオブジェクトのメンバ変数にアクセスする必要があるのかわかりません。したがって、 static メソッドでメンバ変数、メソッドアクセス時に、上記のようなコンパイルエラーが発生します。

メンバ変数とメソッドにアクセスするときは、以下のようにthisが省略されていると考えると理解しやすいです。 this はオブジェクト自身を意味しますが、 static はオブジェクト生成なしで使用するメソッドなので、 static メソッドの中で this は指す対象がなくなります。

public void printUserName() {
    printSomething(this.name);
    printSomething(this.getUserName());
}

2. staticでアクセス可能な変数とメソッド

以下の例のように、 static メソッド staticPrintUserName() は static 変数とメソッドを呼び出すことができます。

public class User {
    private static Boolean DEBUG = true;
    private String name;

    public User(String name) {
        this.name = name;
    }

    public static void staticPrintUserName() {
        if (DEBUG) {
            System.out.println("It's running with debug mode.");
        }
        if (User.DEBUG) {
            printSomething("Do something!");
        }
    }

    public static void printSomething(String str) {
        System.out.println(str);
    }
}

static メソッドは生成されたオブジェクトからの呼び出しも可能で、

User user = new User("John Doe");
user.staticPrintUserName();

オブジェクトが作成されなくても、クラス名で直接メソッドを呼び出すこともできます。

User.staticPrintUserName();

static メソッドの属性がオブジェクト生成なしで呼び出せるため、static メソッドでメンバ変数やメソッドにアクセスしてはいけません。

以下のように staticPrintUserName() からメンバメソッド printUserName() を呼び出そうとすると、コンパイルエラーが発生します。

public class User {
    private static Boolean DEBUG = true;
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void printUserName() {
        printSomething(name);
    }

    public static void staticPrintUserName() {
        printUserName();
    }

    public static void printSomething(String str) {
        System.out.println(str);
    }
}

Output:

src/main/java/User.java:15: error: non-static method printUserName() cannot be referenced from a static context
        printUserName();
        ^

3. non-static メソッドでアクセス可能な変数とメンバー

non-static メソッドでは、static 変数、メソッドだけでなく、メンバー変数、メンバーメソッドの両方にアクセスできます。

public class User {
    private static Boolean DEBUG = true;
    private String name;

    public User(String name) {
        this.name = name;
    }

    public void printUserName() {
        if (DEBUG) {
            printSomething(name);
        }
    }

    public static void printSomething(String str) {
        System.out.println(str);
    }
}

4. 問題原因の確認と解決方法

エラーは static でメンバ変数とメンバメソッドにアクセスするために発生します。単純ですが、継承関係が複雑なライブラリコードを見たり、呼び出し構造がねじれていてLambdaコードが混在しているとうまくいっていますが、なぜエラーが発生しないのですか?と考えることができます。メソッド呼び出しの順序によく従うと、問題の原因を見つけることができます。

References

Related Posts

codechachaCopyright ©2019 codechacha