메서드란 정의 구조 호출·값 전달 반환값·void 오버로딩 static 살짝 📝 문제풀이
◀ 이전 📋 목차 CH 10 ▶
🧩 CHAPTER 09 · 중급

코드에 이름을 붙여, 다시 쓰다

똑같은 코드를 여기저기 복사·붙여넣기 하고 있나요? 메서드(method)는 그 코드에 이름을 붙여 한 번 만들고 몇 번이든 재사용하게 해줘요. 프로그램을 "역할별로 쪼개는" 첫걸음입니다.

🎯 이 장을 끝내면
📖
메서드란
코드에 "이름"을 붙이는 상자
한 문장으로 먼저 잡고, 천천히 풀어볼게요.

메서드(method)는 "어떤 일을 하는 코드 묶음에 이름을 붙여 둔 것"이에요. 이름을 한 번 붙여 두면, 나중에 그 이름만 부르면(호출하면) 안에 든 코드가 통째로 실행돼요. 수학의 함수 f(x)와 비슷하다고 보면 돼요. 다른 언어에서 말하는 "함수(function)"를 자바에서는 메서드라고 부릅니다.

🧩 메서드를 쓰면 좋은 점 2가지 ① 반복을 줄여요 — 같은 코드를 여러 번 쓰는 대신 한 번만 정의하고, 필요할 때마다 이름으로 호출해요. 나중에 고칠 일이 생겨도 한 군데만 고치면 되죠.
② 역할을 나눠요 — 긴 프로그램을 "인사하기", "합계 구하기", "출력하기" 같은 작은 역할로 쪼개면, 읽기 쉽고 관리하기 편해져요. 즉, 메서드는 "복사·붙여넣기"를 "이름 붙여 재사용"으로 바꿔 주는 도구예요. 프로그램이 커질수록 이 습관이 코드를 살립니다.

아래는 우리가 이미 써 본 System.out.println("...")도 사실 메서드 호출이라는 걸 보여줘요. println이라는 "출력하는 메서드"를 부른 거죠. 이번 장에서는 이 메서드를 직접 만드는 법을 배웁니다.

method 호출(call) return void 매개변수(parameter) 인자(argument) 오버로딩 static 재사용
🧭
이번 장의 읽는 법. "정의(만들기) → 호출(부르기) → 값 주고받기(매개변수·return)" 순서로 따라오면 자연스럽게 이해돼요. 예제 코드는 눈으로만 보지 말고, 머릿속으로 "이 값이 어디로 가지?"를 그려 보세요.
🧱
정의 구조
메서드는 이렇게 생겼어요
네 부분으로 나눠서 하나씩 뜯어볼게요.

메서드의 기본 뼈대는 다음과 같아요. 크게 ①반환타입 ②메서드이름 ③매개변수목록 ④본문(그리고 return) 네 부분으로 나뉩니다.

반환타입 메서드이름(매개변수목록) {
    // 실행할 코드 (본문)
    return 값;   // 반환타입이 void가 아니면 값을 돌려줌
}

실제 예로, 두 정수를 더해 결과를 돌려주는 메서드를 만들어 볼게요.

int add(int a, int b) {
    int sum = a + b;
    return sum;
}
🔤
지역변수(local variable) —int sum처럼 메서드 안(또는 { } 블록 안)에서 선언한 변수예요. 그 메서드가 실행되는 동안에만 잠깐 살아 있다가 메서드가 끝나면 사라져요. 그래서 다른 메서드에서는 이 sum을 볼 수 없어요 — 각 메서드는 자기만의 작업 공간을 갖는 셈이죠.
int add (int a, int b) { ... return sum; }
부분예시설명
① 반환타입int이 메서드가 돌려줄 값의 타입. 정수를 돌려주니 int. 아무것도 안 돌려주면 void.
② 메서드이름add호출할 때 부를 이름. 변수 이름 규칙과 같고, 보통 동사로 짓고 소문자로 시작해요(카멜케이스).
③ 매개변수목록int a, int b메서드가 받아 쓸 입력값을 담는 변수. 없으면 괄호 안을 비워요 ().
④ 본문 · returnreturn sum;{ } 안이 실제로 하는 일. return이 결과값을 바깥으로 돌려줘요.
🔤
용어 — 카멜케이스(camelCase). 여러 단어를 붙여 이름 지을 때 첫 단어는 소문자, 뒤 단어의 첫 글자만 대문자로 쓰는 방식이에요(예: getUserName). 중간이 낙타 등처럼 볼록해서 붙은 이름이죠. 자바에서 메서드·변수 이름은 이 관례를 따라요.
💡
반환타입과 return은 짝. 반환타입이 int이면 return으로 반드시 정수 값 하나를 돌려줘야 해요. 반환타입이 void면 돌려줄 값이 없으니 return 값;을 쓰지 않습니다.
📞
호출·값 전달
이름을 부르면, 값이 안으로 들어가요
인자 → 매개변수로 넘어가는 흐름을 눈으로 따라가 봐요.

메서드를 정의했다고 실행되는 게 아니에요. 이름을 불러야(호출해야) 그 안의 코드가 돌아가요. 앞에서 만든 add를 호출해 볼게요.

int result = add(3, 4);   // add 메서드 호출, 3과 4를 넘김
System.out.println(result);   // 7

여기서 호출할 때 넘긴 3, 4인자(argument)라고 해요. 이 인자가 메서드 안의 매개변수(parameter) a, b순서대로 복사되어 들어가요. 즉 a = 3, b = 4가 됩니다.

🔢
add(3, 4)
호출하며 넘긴 값
= 인자(argument)
📥
int a, int b
받는 변수
= 매개변수(parameter)
a=3, b=4
⚙️
a + b
본문 실행
7 계산
📤
return 7
결과를 돌려줌
result = 7
🆚 헷갈리기 쉬운 짝 — 인자 vs 매개변수 인자(argument) — 메서드를 호출할 때 넣어 주는 실제 값. 예: add(3, 4)34.
매개변수(parameter) — 메서드를 정의할 때 그 값을 받기 위해 선언한 변수. 예: int a, int b. 한 줄 정리: 보내는 쪽의 값 = 인자, 받는 쪽의 변수 = 매개변수. 인자가 매개변수 안으로 복사되어 들어가요.

이때 자바는 값을 "복사해서" 전달해요. 이걸 값에 의한 전달(pass by value)이라고 불러요. 그래서 메서드 안에서 매개변수를 바꿔도, 바깥의 원래 변수는 영향을 받지 않아요.

📦
원본 n = 5
바깥에 있는 진짜 변수. 메서드에 넘겨도 그대로 남아요.
복사 →
📄
복사본 x = 5
메서드가 받는 건 값을 베낀 사본. 사본을 고쳐도 원본 n은 안 바뀌어요.
void addOne(int x) {
    x = x + 1;   // 복사본 x만 바뀜
}

int n = 5;
addOne(n);
System.out.println(n);   // 여전히 5 (원본은 안 바뀜)
🧊
값 복사 전달(pass by value). 메서드에 넘어가는 건 원본이 아니라 복사본이에요. 그래서 위 예에서 n은 그대로 5. (참조 타입은 조금 다르게 동작하는데, 그건 객체를 배우는 CH 10 이후에 자연스럽게 알게 돼요. 지금은 "기본형은 복사되어 넘어간다"만 챙기면 충분합니다.)
🔙
반환값·void
돌려주거나(return), 안 돌려주거나(void)
메서드가 결과를 내보내는 두 가지 방식이에요.

return은 메서드의 결과값을 호출한 곳으로 돌려주는 명령이에요. 그리고 return을 만나는 순간 메서드는 즉시 종료돼요 — 그 아래 코드는 실행되지 않습니다.

int max(int a, int b) {
    if (a > b) {
        return a;      // 여기서 끝. 아래로 안 내려감
    }
    return b;
}
return 뒤의 코드는 실행되지 않아요. return을 만나면 메서드가 바로 끝나기 때문에, 그 아래에 코드를 두면 도달할 수 없는 코드(unreachable)가 돼요. 실제로 컴파일 오류가 나기도 합니다.

돌려줄 값이 없는 메서드도 있어요. "화면에 출력만 한다"처럼요. 이럴 땐 반환타입을 void로 씁니다. void"비어 있다"는 뜻이에요.

void sayHello(String name) {
    System.out.println("안녕, " + name + "!");
    // return 값;  없음
}

sayHello("자바");   // 출력: 안녕, 자바!
🆚 값을 돌려주는 메서드 vs void 메서드 반환값 있는 메서드 — 반환타입이 int, String 등. return 값;으로 결과를 돌려주고, 호출한 쪽에서 int r = add(3,4);처럼 값을 받아 쓸 수 있어요.
void 메서드 — 반환타입이 void. 돌려주는 값이 없어요. 그래서 int r = sayHello("자바");처럼 값을 받으려 하면 오류예요. 다만 return;(값 없이)만 써서 메서드를 중간에 끝낼 수는 있어요. 정리: void는 "결과값이 없다"는 뜻이지 "return을 못 쓴다"는 뜻이 아니에요. 값 없는 return;으로 조기 종료는 가능합니다.
void printPositive(int x) {
    if (x <= 0) {
        return;     // 값 없이 그냥 종료 (여기서 끝)
    }
    System.out.println(x + "는 양수예요.");
}
💡
기억하기. return 값; → 값을 돌려주며 종료 (반환타입 필요). return; → 값 없이 그냥 종료 (void에서 사용).
🎭
오버로딩
같은 이름, 다른 얼굴 — 오버로딩
이름은 하나인데 상황에 맞게 여러 버전을 두는 기술이에요.

오버로딩(overloading)같은 이름의 메서드를 여러 개 정의하는 거예요. 단, 조건이 있어요 — 매개변수의 타입이나 개수가 서로 달라야 합니다. 그러면 자바가 호출할 때 넘긴 인자를 보고 알맞은 버전을 알아서 골라 줘요.

int add(int a, int b) {          // 정수 두 개
    return a + b;
}

double add(double a, double b) { // 실수 두 개 (매개변수 타입이 다름)
    return a + b;
}

int add(int a, int b, int c) {   // 정수 세 개 (매개변수 개수가 다름)
    return a + b + c;
}

위 세 개는 이름이 모두 add지만, 매개변수가 달라서 공존할 수 있어요. 호출하는 쪽은 이렇게 씁니다.

add(3, 4);        // int add(int, int)   → 7
add(3.5, 1.5);    // double add(double, double) → 5.0
add(1, 2, 3);     // int add(int, int, int)  → 6
✅ 오버로딩이 되는 조건 / ❌ 안 되는 경우 ✅ 매개변수 타입이 다르면add(int,int) vs add(double,double). 가능!
✅ 매개변수 개수가 다르면add(int,int) vs add(int,int,int). 가능!
❌ 반환타입만 다르면int add(int,int) vs double add(int,int). 불가능! 매개변수가 똑같으면 자바가 어느 걸 부를지 구분할 수 없어서 컴파일 오류가 나요. 핵심: 오버로딩은 매개변수(타입·개수·순서)로 구분해요. 반환타입은 구분 기준이 아니에요.
🔤
메서드 시그니처(signature) — 자바가 메서드를 서로 구별하는 "이름표"로, 메서드 이름 + 매개변수의 타입·개수·순서로 이루어져요. 오버로딩이 되려면 이 시그니처가 서로 달라야 하죠. 중요한 건 반환타입은 시그니처에 안 들어간다는 점이에요 — 그래서 반환타입만 다른 두 메서드는 구별이 안 돼 오류가 나요.
🧠
왜 이름을 여럿 안 만들고 오버로딩을 쓸까? addInt, addDouble처럼 이름을 다 다르게 지으면 외울 게 많아져요. 오버로딩을 쓰면 "더한다 = add" 하나만 기억하면 되고, 나머지는 인자에 맞춰 자바가 골라 줘요. 실제로 System.out.println도 정수·문자열·실수를 모두 받는 오버로딩된 메서드랍니다.
🏷️
static 살짝
main이 static인 이유, 살짝만 맛보기
지금까지 매일 봐 온 그 단어예요. 여기서 조금만 풀어 볼게요.

우리가 매번 쓴 시작점을 떠올려 봐요.

public static void main(String[] args) {
    // 프로그램 시작
}

여기 붙은 static"객체를 만들지 않고, 클래스 이름만으로 바로 쓸 수 있는 메서드"를 뜻해요. 자바 프로그램이 시작될 때는 아직 객체가 하나도 없는 상태예요. 그런데 main이 static이라, 객체 없이도 바로 실행할 수 있어서 프로그램의 진입점이 될 수 있는 거예요.

🔤
진입점(entry point) — 프로그램을 실행하면 맨 처음 시작되는 자리예요. 자바는 무조건 main 메서드부터 실행하기로 약속돼 있어서, main이 바로 그 진입점이에요. 그래서 main이 없거나 형태가 틀리면 프로그램이 "어디서 시작할지 몰라" 실행되지 않아요.

직접 만든 메서드도 static을 붙일 수 있어요. 그러면 같은 클래스의 main에서 객체를 만들지 않고 바로 호출할 수 있어요.

public class Calc {
    static int add(int a, int b) {   // static 메서드
        return a + b;
    }

    public static void main(String[] args) {
        int r = add(3, 4);   // 객체 없이 바로 호출 가능
        System.out.println(r);   // 7
    }
}
🏷️ static 메서드 vs 일반(인스턴스) 메서드 — 아주 간단히 static 메서드객체 없이 클래스 이름으로 호출. 예: Math.max(1, 2). main도 이 부류예요.
일반(인스턴스) 메서드객체를 먼저 만들어야 호출할 수 있어요. 예: "abc".length()처럼 어떤 객체에 붙어 동작해요. 지금은 "main이 static이라 객체 없이 시작된다""static 메서드는 객체 없이 부른다" 정도만 챙기면 충분해요. 객체가 정확히 무엇이고 인스턴스 메서드가 왜 필요한지는 바로 다음 장(CH 10)에서 본격적으로 배웁니다.
🔮
다음 장 예고. "객체 없이"라는 말이 아직 아리송해도 괜찮아요. CH 10 · 클래스와 객체에서 객체를 직접 만들어 보면, static과 인스턴스의 차이가 저절로 선명해집니다.
🧠 이 장 핵심 요약
📝
문제풀이 · 점검
배운 걸 가볍게 점검해봐요
시험이 아니라 "내가 이해했나" 확인용이에요. 틀려도 바로 해설이 나와요.
🧪
문제를 풀면 즉시 정답과 해설이 나오고, 위쪽 바에 점수가 쌓여요. 네 가지 유형(객관식 · O/X · 빈칸 · 코드결과)을 섞어 두었어요. 편하게 눌러보세요.
CH 10 🏗️ 클래스와 객체 — 붕어빵 틀(클래스)로 붕어빵(객체)을 찍어내기