학습 자료

첫 프로그램 — main 을 찾는 이유


Article

지난 강의에서 Hello.java 를 컴파일하고 실행했다. 이번에는 그 파일을 조금 망가뜨려 보자. main 이라는 줄을 통째로 지운다.

public class Hello {
    System.out.println("안녕");
}

컴파일부터 실패한다.

터미널
  • Hello.java:2: error: <identifier> expected
  • System.out.println("안녕");
  • ^

그럼 이번엔 문법은 맞게 두고, 이름만 main 에서 start 로 바꿔보자.

public class Hello {
    public static void start(String[] args) {
        System.out.println("안녕");
    }
}

컴파일은 통과한다. Hello.class 도 잘 생긴다. 그런데 실행하면 이렇다.

터미널
  • 오류: Hello 클래스에서 기본 메소드를 찾을 수 없습니다. 다음 형식으로 기본 메소드를 정의하십시오.
  • public static void main(String[] args)
  • 또는 JavaFX 애플리케이션 클래스는 javafx.application.Application을(를) 확장해야 합니다.

JVM 은 main 이라는 이름을 찾는다. 못 찾으면 아무것도 하지 않고 그냥 나간다. 친절하게 원하는 생김새까지 그대로 적어준다. 마지막 줄은 JavaFX 라는 옛 기술 얘기라 지금은 무시해도 된다.

이번 강의는 저 한 줄을 뜯어본다. 그리고 솔직히 말해두면, 다섯 단어 중 두 개는 여기서 답하지 못한다.

JVM 은 어디서부터 읽어야 할지 모른다

.class 파일 안에는 여러 개의 코드 덩어리가 들어 있을 수 있다. JVM 이 그 파일을 열었을 때, 어느 덩어리부터 실행해야 할까?

정답은 "알 수 없다"이다. 그래서 약속을 정해뒀다.

main 이라는 이름의, 이러이러하게 생긴 덩어리부터 실행한다.

이 약속의 정확한 생김새가 바로 그 한 줄이다.

public static void main(String[] args)

이걸 진입점이라고 부른다. 프로그램이 시작되는 지점이다.

java Hello 를 쳤을 때
  1. JVM 이 뜬다
  2. Hello.class 를 읽는다바이트코드
  3. main 을 찾는다이름도 생김새도 맞아야 한다
  4. 첫 줄부터 실행

다섯 단어

한 단어씩 본다. 지금 다 이해하지 못해도 괜찮다. 이 표는 이 시리즈의 지도이기도 하다.

public static void main(String[] args)
단어지금 알아둘 것제대로 배우는 곳
public바깥에서 불러도 된다는 표시12강
static객체를 만들지 않고도 부를 수 있다13강
void일을 끝내고 돌려주는 값이 없다10강
mainJVM 과 약속한 이름. 바꾸면 못 찾는다여기
String[] args실행할 때 같이 넘긴 글자들9강

publicstatic 은 지금 설명해봤자 와닿지 않는다. 둘 다 객체라는 개념을 알아야 이해되는 말인데, 객체는 11강에 가서야 나온다.

그래서 이렇게 하자. 지금은 "JVM 이 알아볼 수 있게 정해진 대로 적는 주문" 이라고 여기고 넘어간다. 13강에서 static 을 배우고 나면, 저 줄을 다시 보게 될 거다. 그때 "아, 그래서 mainstatic 이었구나" 하는 순간이 온다.

args 는 진짜로 쓸 수 있다

String[] args 를 장식품처럼 넘기기 쉬운데, 실제로 값이 들어온다. 실행할 때 뒤에 글자를 붙이면 된다.

public class Hello {
    public static void main(String[] args) {
        System.out.println("받은 개수: " + args.length);
        System.out.println("첫 번째: " + args[0]);
    }
}
java Hello 사과 바나나
터미널
  • 받은 개수: 2
  • 첫 번째: 사과

args 는 글자 여러 개를 담는 상자다. 이런 상자를 배열이라고 부르고, 9강에서 제대로 다룬다.

아무것도 안 붙이고 그냥 java Hello 를 치면 어떻게 될까? args.length0 이 되고, args[0] 을 꺼내려는 순간 프로그램이 죽는다. 없는 걸 꺼내려 했기 때문이다. 이 죽음의 정체는 18강에서 밝힌다.

System.out.println 도 뜯어보면

우리가 매번 치는 이 긴 주문에도 구조가 있다.

System.out.println("안녕")
  • System자바가 미리 만들어둔 클래스
    • outSystem 안에 들어 있는 것 — 화면으로 통하는 통로
      • println("안녕")통로에 글자를 흘려보낸다. 끝에 줄바꿈을 붙인다

점(.)은 "안으로 들어간다" 는 뜻이다. System 안의 out 을 꺼내고, 그 out 에게 println 을 시킨다.

println 은 print line 의 준말이다. 줄바꿈 없이 찍고 싶으면 print 를 쓴다.

System.out.print("안");
System.out.print("녕");
System.out.println("!");
System.out.println("다음 줄");
콘솔
  • 안녕!
  • 다음 줄

System 을 객체로 만든 적이 없는데 System.out 을 바로 꺼내 쓴 게 이상하지 않은가? 그게 가능한 이유가 static 이다. 13강까지 미뤄둔 그 단어다.

파일 이름은 마음대로 못 정한다

public 이 붙은 클래스는 파일 이름과 클래스 이름이 같아야 한다. 이건 컴파일러가 강제한다.

Hello.java 안에 public class Greeting 이라고 쓰면 이렇게 혼난다.

터미널
  • Hello.java:1: error: class Greeting is public, should be declared in a file named Greeting.java

친절하게 파일 이름까지 알려준다. 자바 컴파일러는 인색하지만 정확하다.

그리고 클래스 이름은 관례상 대문자로 시작한다. Hello, Greeting, UserService. 단어가 여러 개면 각 단어의 첫 글자를 대문자로 붙여 쓴다.

두 종류의 에러를 구분한다

지금까지 본 에러는 사실 두 부류였다. 이 구분을 지금 잡아두면 앞으로 편하다.

언제 난 에러인가

컴파일 에러

javac 가 낸다 · .class 가 안 생긴다

  • error: 로 시작하고 줄 번호를 알려준다
  • 클래스 이름과 파일 이름이 다를 때
  • 세미콜론을 빠뜨렸을 때
  • 프로그램이 실행조차 되지 않는다

실행 에러

JVM 이 낸다 · 돌다가 죽는다

  • 오류: 또는 Exception 으로 시작한다
  • main 을 못 찾을 때
  • 없는 값을 꺼내려 할 때
  • 여기까지는 잘 돌았다는 뜻이기도 하다

에러 메시지를 보면 어느 쪽인지 먼저 가늠하는 습관을 들이자. 컴파일 에러는 내가 문법을 틀린 것이고, 실행 에러는 문법은 맞았는데 상황이 틀어진 것이다. 고치는 방법이 완전히 다르다.

주석 — 컴파일러가 무시하는 글자

코드 사이에 사람이 읽을 말을 끼워 넣을 수 있다. javac 는 이걸 통째로 건너뛴다.

public class Hello {
    // 한 줄 주석. 이 줄 끝까지 무시된다.

    /*
       여러 줄 주석.
       닫을 때까지 전부 무시된다.
    */

    public static void main(String[] args) {
        System.out.println("안녕"); // 코드 뒤에 붙여도 된다
    }
}

주석은 바이트코드에 남지 않는다. 1강에서 본 .class 파일에는 흔적조차 없다.

정리하면

JVM 은 main 이라는 약속된 이름의 진입점을 찾아 거기서부터 실행한다.

다시 짚어보기
  1. 01

    진입점은 main 이다

    이름을 바꾸면 컴파일은 되지만 실행이 안 된다. 키워드가 아니라 약속이다.

  2. 02

    다섯 단어 중 셋은 나중에 답한다

    public 은 12강, static 은 13강, void 는 10강. 지금은 정해진 대로 적는다.

    public static void main(String[] args)
  3. 03

    args 에는 실행할 때 붙인 글자가 들어온다

    배열이라는 상자다. 9강에서 다룬다.

    java Hello 사과 바나나
  4. 04

    public 클래스 이름 = 파일 이름

    다르면 컴파일러가 파일 이름까지 알려주며 거절한다.

  5. 05

    에러는 두 종류다

    컴파일 에러는 javac 가, 실행 에러는 JVM 이 낸다.

Part 1 이 끝났다. 두 강의를 요약하면 이렇다. 우리가 쓴 텍스트를 javac 가 바이트코드로 옮기고, JVM 이 그 바이트코드에서 main 을 찾아 실행한다. 자바를 배우는 동안 이 그림은 바뀌지 않는다.

이제 껍데기를 벗어나 안으로 들어간다. 다음 강의부터는 main 의 중괄호 안쪽만 본다.

첫 순서는 변수다. 자바에서 값에 이름을 붙이려면 이름 앞에 한 가지를 더 적어야 한다. 그게 무엇이고, 컴파일러가 왜 그 귀찮은 걸 시키는지 본다.

첫 프로그램 — main 을 찾는 이유 — 디코드랩(DCODELAB)