Java - non-static method cannot be referenced from a static context

개발하다보면 아래와 같이 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 method는 객체 생성 없이 사용할 수 있기 때문에, Static method 내부에서 멤버 변수 또는 메소드를 사용할 수 없습니다. 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

Loading script...

Related Posts

codechachaCopyright ©2019 codechacha