우리는 너무도 쉽게 System.out.println()
을 사용한다.
다음은 Hello world!
를 출력하는 코드이다.
public class Main {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
Hello World!
그런데 이런 생각을 한 적 있는가?
println()
메서드는 PrintStream
클래스의 메서드이지만 코드 어디에도 PrintStream
이라는 이름은 찾을 수 없다. 게다가 System.out.println()
대신 PrintStream.println()
을 사용하면 컴파일 에러가 발생한다.
java: non-static method println(java.lang.String) cannot be referenced from a static context
println()
메서드는 인스턴스(non-static) 메서드이기 때문에 클래스를 통해 외부로 호출할 수 없다. 이는 PrintStream
클래스의 내부 코드를 보면 알 수 있다.
public void println(String x) { // non-static method
synchronized (this) {
print(x);
newLine();
}
}
여기서 만약 println()
메서드를 사용하려면 java.io
패키지를 import
하고 PrintStream
클래스에 대한 객체를 생성해야 한다. 그러나 System.out
은 import
조차 없이 println()
메서드를 호출한다. 대체 System.out
이 뭘까?
먼저 System
클래스는 java.lang
패키지에 속한 클래스이다. java.lang
패키지는 컴파일 단계에서 암묵적으로(implicitly) 다음과 같이 추가된다.
import java.lang.*
이 때문에 우리는 java.lang
패키지를 명시하지 않아도 System
클래스를 사용할 수 있다.
자바에서는 점 표기법(dot notation)을 통해 클래스의 속성(attribute)에 접근한다. 즉 System.out
에서 out
은 System
클래스의 필드 또는 메서드이다.
public final class System {
...
public static final PrintStream out = null;
...
}
다음과 같이 System
클래스는 out
이라는 이름의 PrintStream
클래스 변수(상수)를 필드로 가진다. 위에서 살펴보았듯이 PrintStream
클래스는 println()
메서드를 포함하기 때문에 우리는 System.out
객체를 통해 println()
메서드를 호출할 수 있다!
println()
메서드는 PrintStream
클래스의 인스턴스 메서드이다.java.lang
패키지는 컴파일 단계에서 묵시적으로 선언되므로 java.lang.System
클래스는 import
로 명시하지 않아도 된다.System
클래스는 PrintStream
클래스 타입의 필드를 가진다(==out
). 정적(static)으로 선언되어 있기 때문에 어디서든 System.out
과 같이 클래스를 통해 호출할 수 있다 (애초에 System
클래스는 인스턴스 생성이 안 된다. private
생성자로 막아두었기 때문).https://docs.oracle.com/javase/8/docs/api/
https://stackoverflow.com/questions/16590651/does-the-system-out-object-belong-to-class-system-or-class-printstream
https://milhouse93.tistory.com/54
끝.
안녕하세요 궁금한 부분이 있는데요,
out은 public static PrintStream out = null; 이라고 선언되어있는데
왜 System.out.println() 을 불러올 때 NPE가 발생하지 않는걸까요?