반응형

바쁜 분은 이것만

  1. main은 static이라 객체 없이 실행된다 → 인스턴스 메서드·변수는 객체를 만들어서 부른다: new 클래스명().메서드()
  2. 객체의 값(필드)을 안 쓰는 계산용 메서드라면 static을 붙여도 된다
  3. static 필드는 모든 객체가 하나를 같이 쓴다 — 객체마다 다른 값이면 static을 붙이지 않는다

자바를 처음 배울 때 main 안에서 내가 만든 메서드를 부르자마자 non-static method ... cannot be referenced from a static context 에러를 자주 만납니다. "static이 아닌 메서드를 static 영역에서 참조할 수 없다"는 뜻인데, 왜 그런지와 실제로 고치는 방법 두 가지를 OpenJDK 27에서 직접 컴파일해 보며 정리했습니다.

1. 에러 재현: main에서 메서드와 변수를 바로 쓸 때

public class N1 {
    int count = 0;

    void hello() {
        System.out.println("안녕하세요");
    }

    public static void main(String[] args) {
        hello();
        count = 5;
    }
}
N1.java:9: error: non-static method hello() cannot be referenced from a static context
        hello();
        ^
N1.java:10: error: non-static variable count cannot be referenced from a static context
        count = 5;
        ^
2 errors

메서드는 non-static method, 필드는 non-static variable로 나올 뿐 원인은 같습니다.

  • hello()와 count에는 static이 없으니 객체(인스턴스)에 속한 것입니다.
  • main은 static이라 객체를 하나도 만들지 않은 상태에서 실행됩니다.
  • 그러니 main 안에서 그냥 count라고 쓰면 "어느 객체의 count?"가 정해지지 않아 컴파일러가 막는 것입니다.

2. 해결 ①: 객체를 만들어서 호출하기 (기본)

public class N2 {
    int count = 0;

    void hello() {
        System.out.println("안녕하세요");
    }

    public static void main(String[] args) {
        N2 app = new N2();
        app.hello();
        app.count = 5;
        System.out.println("count = " + app.count);
    }
}
안녕하세요
count = 5

new N2()로 객체를 만들고 app.hello()처럼 "이 객체의"를 붙여 부르면 됩니다. 메서드가 필드를 쓰거나, 나중에 객체를 여러 개 만들 수도 있는 구조라면 이 방법이 맞아요.

3. 해결 ②: 메서드에 static 붙이기 (괜찮은 경우)

public class N3 {
    static int add(int a, int b) {
        return a + b;
    }

    public static void main(String[] args) {
        System.out.println("3 + 4 = " + add(3, 4));
        System.out.println("Math.max = " + Math.max(3, 4));
    }
}
3 + 4 = 7
Math.max = 4

add는 매개변수로 받은 값만 계산하고 객체의 필드를 전혀 쓰지 않습니다. 이런 메서드는 static으로 만들어도 문제가 없고, 객체 없이 바로 부를 수 있어요. 표준 라이브러리의 Math.max()도 같은 이유로 static입니다.

주의할 점은 에러를 없애려고 필드까지 줄줄이 static으로 바꾸는 것입니다. 컴파일은 되지만 다음 4번처럼 의도와 다르게 동작할 수 있어요.

4. static 필드는 모든 객체가 공유한다 (카운터 실측)

public class Counter {
    static int total = 0;   // 모든 객체가 같이 쓰는 값
    int mine = 0;           // 객체마다 따로 있는 값

    void click() {
        total++;
        mine++;
    }

    public static void main(String[] args) {
        Counter a = new Counter();
        Counter b = new Counter();
        a.click();
        a.click();
        b.click();
        System.out.println("a.mine = " + a.mine + ", b.mine = " + b.mine);
        System.out.println("a.total = " + a.total + ", b.total = " + b.total);
        System.out.println("Counter.total = " + Counter.total);
    }
}
a.mine = 2, b.mine = 1
a.total = 3, b.total = 3
Counter.total = 3

a를 두 번, b를 한 번 눌렀더니 mine은 객체마다 따로 2와 1이 됐고, total은 a로 보든 b로 보든 3으로 같습니다. static 필드는 객체마다 생기는 게 아니라 클래스에 하나만 있기 때문이에요. 그래서 Counter.total처럼 클래스 이름으로 읽는 게 정석입니다.

1번 에러를 없애려고 이름·점수 같은 값을 static으로 바꾸면, 객체가 여러 개일 때 마지막에 넣은 값 하나로 덮입니다. 정말 공유할 값에만 static을 씁니다.

5. static 메서드에서 this를 쓸 때

public class N4 {
    String name = "백조";

    static void printName() {
        System.out.println(this.name);
    }

    public static void main(String[] args) {
        printName();
    }
}
N4.java:5: error: non-static variable this cannot be referenced from a static context
        System.out.println(this.name);
                           ^
1 error

this는 "지금 이 메서드를 부른 객체"인데, static 메서드는 객체 없이 불리니 가리킬 대상이 없습니다. 고치는 방법은 static을 빼서 인스턴스 메서드로 만들거나, 객체를 매개변수로 받는 것입니다.

public class N5 {
    String name = "백조";

    void printName() {
        System.out.println(this.name);
    }

    static void printName(N5 obj) {
        System.out.println(obj.name);
    }

    public static void main(String[] args) {
        N5 n = new N5();
        n.printName();
        printName(n);
    }
}
백조
백조

6. 같은 에러가 나는 경우: 안쪽 클래스를 main에서 new 할 때

클래스 안에 클래스를 만들고 main에서 객체를 만들 때도 똑같은 this 메시지가 나옵니다.

public class N7 {
    class Item {
        String name = "연필";
    }

    public static void main(String[] args) {
        Item it = new Item();
        System.out.println(it.name);
    }
}
N7.java:7: error: non-static variable this cannot be referenced from a static context
        Item it = new Item();
                  ^
1 error

static이 없는 안쪽 클래스(inner class)는 바깥 클래스의 객체에 붙어서 만들어지는데, main에는 바깥 객체(this)가 없어서입니다. 안쪽 클래스가 바깥 객체의 필드를 쓰지 않는다면 static class로 선언하면 됩니다.

public class N8 {
    static class Item {
        String name = "연필";
    }

    public static void main(String[] args) {
        Item it = new Item();
        System.out.println(it.name);
    }
}
연필

바깥 객체가 꼭 필요한 inner class라면 new N7().new Item()처럼 바깥 객체를 먼저 만들어서 생성합니다.

정리: 언제 static을 붙이나

상황 static? 예
객체마다 값이 다른 필드 X 이름, 점수, 잔액
모든 객체가 같이 쓰는 값 O 전체 생성 개수, 상수(static final)
필드를 쓰는 메서드 X click(), printName()
매개변수만으로 계산하는 메서드 O 가능 add(a, b), Math.max()
바깥 객체를 안 쓰는 안쪽 클래스 O 가능 static class Item
에러 메시지 해결
non-static method X() cannot be referenced... new 클래스().X() 또는 X를 static으로
non-static variable X cannot be referenced... 객체.X로 접근 (공유 값일 때만 static)
non-static variable this cannot be referenced... static 메서드에서 this 제거, 또는 inner class를 static class로

참고: Java Language Specification 8.3.1.1 static Fields, 8.4.3.2 static Methods, 8.1.3 Inner Classes and Enclosing Instances, 15.8.3 this; Oracle The Java Tutorials "Understanding Class Members", "Nested Classes"

반응형

+ Recent posts