개발하다보면 아래와 같이 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
Related Posts
- Java - Unsupported class file major version 61 에러
- Java - String.matches()로 문자열 패턴 확인 및 다양한 예제 소개
- Java - 문자열 공백제거 (trim, replace)
- Java - replace()와 replaceAll()의 차이점
- Java - ArrayList 초기화, 4가지 방법
- Java - 배열 정렬(Sorting) (오름차순, 내림차순)
- Java - 문자열(String)을 비교하는 방법 (==, equals, compare)
- Java - StringBuilder 사용 방법, 예제
- Java - 로그 출력, 파일 저장 방법 (Logger 라이브러리)
- Java IllegalArgumentException 의미, 발생 이유
- Java - NullPointerException 원인, 해결 방법
- Seleninum의 ConnectionFailedException: Unable to establish websocket connection 해결
- Java - compareTo(), 객체 크기 비교
- Java - BufferedWriter로 파일 쓰기
- Java - BufferedReader로 파일 읽기
- Java charAt() 함수 알아보기
- Java - BigInteger 범위, 비교, 연산, 형변환
- Java contains()로 문자(대소문자 X) 포함 확인
- Java - Set(HashSet)를 배열로 변환
- Java - 문자열 첫번째 문자, 마지막 문자 확인
- Java - 문자열 한글자씩 자르기
- Java - 문자열 단어 개수 가져오기
- Java - 1초마다 반복 실행
- Java - 배열을 Set(HashSet)로 변환
- Java - 여러 Set(HashSet) 합치기
- Java - 명령행 인자 입력 받기
- Java - 리스트 역순으로 순회, 3가지 방법
- Java - 특정 조건으로 리스트 필터링, 3가지 방법
- Java - HashMap 모든 요소들의 합계, 평균 계산
- Java - 특정 조건으로 HashMap 필터링
- Java - 싱글톤(Singleton) 패턴 구현
- Java - 숫자 왼쪽에 0으로 채우기
- Java - String 배열 초기화 방법
- Java - 정렬된 순서로 Map(HashMap) 순회
- Java - HashMap에서 key, value 가져오기