우리는 너무도 쉽게 System.out.println()을 사용해

한시온·2022년 3월 4일
1
post-thumbnail

Hello World!

우리는 너무도 쉽게 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.outimport 조차 없이 println() 메서드를 호출한다. 대체 System.out이 뭘까?

java.lang.System

먼저 System 클래스는 java.lang 패키지에 속한 클래스이다. java.lang 패키지는 컴파일 단계에서 암묵적으로(implicitly) 다음과 같이 추가된다.

import java.lang.*

이 때문에 우리는 java.lang 패키지를 명시하지 않아도 System 클래스를 사용할 수 있다.

out

자바에서는 점 표기법(dot notation)을 통해 클래스의 속성(attribute)에 접근한다. 즉 System.out에서 outSystem 클래스의 필드 또는 메서드이다.

	public final class System {
      ...
      
      public static final PrintStream out = null;
      
      ...
	}

다음과 같이 System 클래스는 out이라는 이름의 PrintStream 클래스 변수(상수)를 필드로 가진다. 위에서 살펴보았듯이 PrintStream 클래스는 println() 메서드를 포함하기 때문에 우리는 System.out 객체를 통해 println() 메서드를 호출할 수 있다!

결론

  1. println() 메서드는 PrintStream 클래스의 인스턴스 메서드이다.
  2. java.lang 패키지는 컴파일 단계에서 묵시적으로 선언되므로 java.lang.System 클래스는 import로 명시하지 않아도 된다.
  3. 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

끝.

profile
가볍고 무겁게

1개의 댓글

comment-user-thumbnail
2023년 4월 23일

안녕하세요 궁금한 부분이 있는데요,
out은 public static PrintStream out = null; 이라고 선언되어있는데
왜 System.out.println() 을 불러올 때 NPE가 발생하지 않는걸까요?

답글 달기