개발 학습 실습실

이 사이트의 실습은 자바스크립트를 켜야 움직입니다. 아래는 같은 내용을 글로 적은 것입니다.

기초개념 › Java

메서드

메서드는 무엇이고, 선언하는 것과 부르는 것은 어떻게 다른가

메서드는 이름을 붙여 둔 코드 묶음입니다. 코드에서 static int add(int a, int b) { ... }처럼 이름과 괄호, 중괄호로 적은 부분이 메서드의 선언입니다. 선언은 "add라는 이름의 코드 묶음이 있다"고 적어 둔 것일 뿐이어서, 선언만으로는 그 안의 코드가 실행되지 않습니다. 실행은 add(2, 3)처럼 이름 뒤에 괄호를 붙여 부를 때 일어납니다. 부를 때 괄호 안에 넘긴 값 2와 3이 선언의 괄호 안 변수 a와 b(매개변수)에 담기고, return이 계산한 값을 부른 곳으로 돌려줍니다. 이 실습은 선언과 부르는 줄을 하나씩 지우고 부르는 횟수와 넘기는 값의 개수를 바꿔 가며 같은 코드를 컴파일하고 실행해, 컴파일러가 무엇을 알려 주고 add가 몇 번 실행되는지를 봅니다. (static은 main이 객체를 만들지 않고 바로 부를 수 있게 붙인 것으로 보고, 이 실습에서는 다루지 않습니다.)

실행으로 대조 · JDK 21에서 열두 가지 조합을 javax.tools로 컴파일하고 실행해 대조

이 실습에 나오는 개념

메서드
메서드는 이름을 붙여 둔 실행 코드 묶음으로, 호출할 때 정해진 개수의 값을 넘겨받을 수 있다. 선언은 static int add(int a, int b) { ... }처럼 반환 타입, 이름, 괄호 안의 매개변수 목록, 중괄호로 묶은 본문으로 이루어진다. 선언은 "이런 코드 묶음이 있다"고 적어 둔 것일 뿐이어서, 선언만으로는 본문이 실행되지 않고 호출될 때 실행된다. 본문이 블록이면 그 블록이 비어 있어도 구현한 메서드이다. 반환 타입을 선언한 메서드는 본문이 끝까지 그냥 흘러 나가면 컴파일 오류이므로 return 등으로 끝나야 한다.
메서드 호출
메서드 호출은 add(2, 3)처럼 메서드 이름 뒤에 괄호를 붙이고 괄호 안에 넘길 값을 적어 그 메서드의 본문을 실행시키는 식이다. 컴파일러는 호출마다 그 이름의 메서드를 찾고, 고정 인자 메서드라면 넘긴 값의 개수가 매개변수의 개수와 같은지 확인한다. 그 이름의 메서드가 없거나 개수가 맞지 않아 부를 수 있는 메서드가 하나도 없으면 컴파일 오류이다. 실행할 때는 넘기는 값을 왼쪽부터 차례로 계산하고, 그 값을 새로 만든 매개변수 변수에 담은 뒤 본문을 실행한다. 같은 메서드를 두 번 부르면 본문도 두 번 실행된다.
매개변수와 인자
매개변수는 메서드 선언의 괄호 안에 적은 변수이고, 인자는 메서드를 부를 때 괄호 안에 넘기는 값이다. add(int a, int b)의 a와 b가 매개변수이고, add(2, 3)의 2와 3이 인자이다. 메서드를 부르면 인자의 값이 호출마다 새로 만들어지는 매개변수 변수에 차례로 담긴 뒤 본문이 실행되고, 본문 안에서는 매개변수의 이름을 변수처럼 쓴다. 한 메서드에 같은 이름의 매개변수를 두 개 선언하면 컴파일 오류이다.
반환값(return)
return은 메서드의 실행을 끝내고 제어를 그 메서드를 부른 곳으로 돌려보내는 문장이다. return a + b처럼 식을 붙이면 식을 먼저 계산하고, 그 값이 호출의 값이 되어 int sum = add(2, 3);의 add(2, 3) 자리를 대신한다. 값을 붙인 return은 void로 선언한 메서드나 생성자에서 쓰면 컴파일 오류이고, 식의 타입은 선언한 반환 타입에 맞아야 한다. return은 try 안에서 쓰였을 때 finally를 먼저 실행한 뒤에 제어를 넘긴다.

이렇게 바꿔 보세요

처음 설정으로 실행하면

  1. javac로 컴파일합니다. 컴파일러가 소스를 위에서부터 읽으면서 add 메서드의 선언을 만납니다. 선언은 "add라는 이름의 코드 묶음이 있고, int 값 두 개를 받아 int 값 하나를 돌려준다"고 적어 둔 것입니다. 괄호 안의 int a, int b는 부를 때 넘겨받을 값을 담는 변수로, 매개변수라고 합니다. 컴파일러는 이 이름을 기억해 둘 뿐이고, 컴파일은 실행이 아니므로 add 안의 코드는 실행되지 않습니다.
  2. 컴파일러가 main 안의 add(2, 3) 호출을 읽습니다. 이름 add를 선언에서 찾았고, 넘기는 값이 두 개(2, 3)로 매개변수 두 개(a, b)와 개수가 맞습니다. 통과입니다.
  3. 컴파일이 성공해 실행할 Main 클래스 파일이 만들어집니다.
  4. java Main으로 실행합니다. 실행은 main의 첫 줄부터 시작합니다. 소스에는 add 선언이 main보다 위에 적혀 있지만, 소스에 적힌 순서대로 실행되는 것이 아닙니다. 선언은 실행 순서에 들어가지 않고, 이 시점까지 add의 코드는 한 번도 실행되지 않았습니다.
  5. int sum = add(2, 3); 줄에서 add(2, 3) 호출을 만납니다. 이름 뒤에 괄호를 붙인 이 모양이 add를 부르는 것이고, 괄호 안의 2와 3이 넘기는 값입니다. 넘긴 값이 add의 매개변수에 차례로 담깁니다. 2는 a에, 3은 b에 담기고, 실행이 main에서 add 안의 코드로 옮겨 갑니다.
  6. add 안의 첫 줄 System.out.println("add 실행")이 실행되어 add 실행을 출력합니다. add가 실행된 횟수는 1번입니다.
  7. return a + b가 a + b를 계산하고(2 + 3은 5), 그 값 5를 add를 부른 곳으로 돌려줍니다. add의 실행은 여기서 끝나고, 실행은 main으로 돌아옵니다.
  8. add(2, 3) 호출이 있던 자리가 돌려받은 값 5가 되어, 5가 sum에 담깁니다.
  9. System.out.println(sum) 줄이 sum에 담긴 5를 출력합니다.

실행 결과

코드

public class Main {
    // 선언: add라는 이름의 코드 묶음. 부르기 전에는 실행되지 않는다
    static int add(int a, int b) {
        System.out.println("add 실행");
        return a + b;
    }

    public static void main(String[] args) {
        // 호출: 2와 3을 넘겨 add를 실행하고, 돌려받은 값을 sum에 담는다
        int sum = add(2, 3);
        System.out.println(sum);
    }
}

이 모형의 전제

컴파일러와 실행 환경은 JDK 21.0.12.1(javac 21)입니다. 열두 가지 조합을 모두, 화면의 코드와 같은 소스(줄 단위로 같은 글)를 javax.tools로 컴파일하고, 컴파일에 성공한 것은 클래스 파일을 새 클래스 로더로 읽어 Main.main을 실행해 표준 출력을 잡은 결과와 대조했습니다. 대조한 것은 컴파일 성공 여부, 첫 번째 오류의 진단 코드(compiler.err.cant.resolve.location.args와 compiler.err.cant.apply.symbol을 화면의 두 가지 오류 설명으로 옮겼습니다), 오류의 개수와 오류가 난 줄, Main 클래스 파일이 만들어졌는지, 실행했을 때의 출력과 그 출력에 "add 실행"이 나온 횟수입니다. 단계 문장이 기대는 "실행은 main의 첫 줄부터 시작하고, add 선언이 main보다 위에 있어도 먼저 실행되지 않는다"는 사실은, main의 첫 줄에 출력 줄을 하나 더한 별도의 소스를 같은 방식으로 실행해 main 시작, add 실행, 5의 순서로 출력되는 것을 확인했습니다. 문서는 Java Language Specification(Java SE 21)을 직접 열어 확인했습니다. 메서드 선언이 호출할 수 있는 실행 코드를 선언한다는 것은 8.4절, 호출할 때 넘긴 값이 본문을 실행하기 전에 새로 만들어진 매개변수 변수를 초기화한다는 것은 8.4.1절, 메서드 본문이 블록이면 구현이라는 것은 8.4.7절, 호출할 때 인자 식을 왼쪽부터 차례로 계산한다는 것은 15.12.4.2절, 인자 값이 새로 만들어진 매개변수 변수에 담긴 뒤 메서드 본문으로 제어가 넘어간다는 것은 15.12.4.5절, 값이 있는 return이 식을 계산하고 그 값이 호출의 값이 되며 제어를 호출한 곳으로 넘긴다는 것은 14.17절, 인자 개수가 같은 메서드만 호출 후보가 된다는 것(고정 인자 메서드의 경우)과 후보가 하나도 없으면 컴파일 오류라는 것은 15.12.2.1절을 따랐습니다. 15.12.2.1절은 문서의 일부만 읽을 수 있었고 8.4.5절(반환 타입)은 열어 보지 못했습니다. 오류의 종류, 개수, 어느 줄에서 나는지는 명세가 정한 것이 아니라 이 javac에서 관찰한 것입니다. 이 밖에 반환 타입이 void인 메서드, 같은 이름의 메서드를 여러 개 만드는 것(오버로딩), 객체에 속한 메서드, 가변 인자는 다루지 않았고, 메서드를 부를 때마다 실행 정보가 쌓였다 사라지는 방식은 "세부 동작 실습: 스택과 힙"에서 다룹니다.

앞 실습: 변수와 타입 · 다음 실습: 클래스와 객체

이 실습에 나오는 개념

이 실습에서 보는 것

설정

코드


      
    

그림

실행 비교

이렇게 바꿔 보세요