메서드(method)

메서드는 간단히 말하자면 어떤 작업을 수행하는 문장들을 묶어놓은 것이라고 할 수 있습니다. 우리는 이미 자바를 살펴보면서 이미 메서드를 본적이 있습니다. 그것은 바로 프로그램의 진입점(Entry Point)으로 프로그램에서 중요한 역할을 담당했던 main 메서드입니다. 이 문서에서는 직접 메서드를 정의하여 호출하는 방법에 대해서 알아보도록 하겠습니다. 메서드의 기본 구성을 살펴보면 아래와 같습니다.

[제어자] 반환형 메서드명(매개변수1, 매개변수2, ...) {
	// ...
}

뭔가 새로 보는 게 많아 보이지만 차근차근 살펴보도록 합시다. 우선 제어자(modifier)는 여기서 설명하지 않습니다. 제어자를 이해하려면 객체와 클래스를 이해해야 하므로 객체와 클래스 편과 접근 제어자 편에서 따로 설명합니다.

반환형(return type)

반환형에서 반환(return)은 무엇일까요? 이름에서 짐작이 가는 분들도 계시겠지만 반환은 사전적 정의 그대로 빌리거나 차지했던 것을 되돌려준다는 뜻을 가지고 있습니다. 즉, 메서드를 호출한 영역으로 값을 돌려보내는 것을 말합니다. 반환형은 돌려보내는 값이 어떤 타입인지 말해주는 역할을 합니다. 이해를 돕기 위해서 아래의 예제를 컴파일한 후에 실행하여 봅시다.

public class MethodExamples {
	public static void main(String[] args) {
		sum(10, 6);
	}
	
	static void sum(int a, int b) {
		System.out.println(a + b);
	}
}

위의 예제에서 제어자에 static이 쓰였지만 이를 이해하려면 다른 개념들을 먼저 배워야 하므로 추후에 살펴보도록 하겠습니다. 반환형으론 void가 왔는데 이건 무슨 뜻일까요? void는 "해당 메서드는 값을 반환하지 않습니다."라는 의미를 지니고 있습니다. 이어서 코드를 살펴보면, 3행에서 sum()를 호출함과 동시에 제어권이 main()에서 호출한 메서드 sum()으로 넘어갑니다. sum() 메서드에서 할 일이 다 끝나면 제어권을 다시 메인 메서드로 돌려주게 되면서, 이어서 코드를 실행하기 시작합니다.

이번에는 한번 아래와 같이 코드를 수정해 볼까요?

public class MethodExamples {
	public static void main(String[] args) {
		System.out.println(sum(10, 6));
	}
	
	static int sum(int a, int b) {
		return a + b;
	}
}

이번에는 return을 사용해서 변수 a와 변수 b를 서로 더한 값을 메서드 sum()을 호출한 영역으로 돌려보내고 있습니다. 여기서 서로 더한 값은 int형이므로 반환형도 int형이 됩니다. 예를 들어서, 반환하려는 값의 타입이 double형이라면 반환형은 double이 되어야 합니다. return 키워드는 호출한 영역으로 값과 제어권을 돌려보냄과 동시에 메서드를 종료하는 기능을 합니다. 위와 같이 코드를 수정하면 결과값을 활용할 수 있으므로 아래와 같이 작성할 수도 있습니다.

public class MethodExamples {
	public static void main(String[] args) {
		System.out.println(sum(sum(10, 6), sum(5, 10)));
		System.out.println(sum(1, 2) * sum(3, 4));
	}
	
	static int sum(int a, int b) {
		return a + b;
	}
}

3행을 자세히 살펴보면 아래와 같은 과정을 거친다는 걸 알 수 있습니다.

4행에 있는 연산식 'sum(1, 2) * sum(3, 4)'도 마찬가지로 '3 * 7'이 되어 21이란 결과가 나옵니다. 유용하죠?

위와 같이 작성하면 먼저 return문을 만나 메서드가 종료되어 버리므로 그 아래에 있는 코드는 도달할 수 없는 코드가 되어버립니다. 반환형이 void일 때도 아래와 같이 return문을 사용할 수 있습니다. 이때는 값을 반환하는 것 없이 메서드를 종료시키는 역할만 합니다.

static void div(int a, int b) {
  if (b == 0) {
    System.out.println("0으로 나눌 수 없습니다.");
    return;
  }
  System.out.println(a / b);
}

매개변수(parameter)

매개변수는 무엇일까요? 위에서 이미 짐작이 가시는 분들도 있겠지만, 매개변수는 메서드로 전달된 값을 받는 변수를 말합니다. 메서드를 호출할 때 소괄호 안에 값을 콤마(,)로 구분하여 값을 전달합니다. 이렇게 전달된 값은 메서드의 매개변수로 순서대로 넘어갑니다. 전달되는 값의 개수는 매개변수 개수와 일치해야 하며, 전달된 값과 대응된 매개변수의 타입도 서로 일치해야 합니다.

변수의 생존범위

생존범위를 이해하기 전에 블록(block)이란 개념을 이해해야 합니다. 위키백과에서 정의를 빌려오자면 블록은 프로그래밍에서 마치 한 문단처럼 보이는, 코드의 한 부분을 뜻합니다. 자바에서 블록은 여는 중괄호({)로 시작해서 닫는 중괄호(})로 끝납니다. 블록은 아래와 같이 블록 저마다 고유한 영역을 만듭니다.

모든 변수는 생성된 영역 안에서만 접근할 수 있습니다. 생성된 영역은 변수를 선언한 시점에서 자신을 둘러싸는 블록의 끝까지를 말합니다. 변수의 생존범위는 나중에 배울 개념들을 소개할 때 추가적으로 설명하겠습니다.

블록 영역

아래 예제 코드에서 10행의 주석 처리를 해제하고 컴파일하면 에러가 발생합니다.

public class MethodExamples {
	public static void main(String[] args) {
		int a = 5, b = 4;
		
		if (a > b) {
			int temp = a;
			a = b;
			b = temp;
		}
        // System.out.println(temp);
		System.out.println(a + " " + b);
	}
}

아래 그림에서 볼 수 있듯이 외부 블록에서 내부 블록에 선언된 변수에 접근할 수 없기 때문입니다. 만약에, 외부 블록에서 접근하려면 변수 temp를 if문 밖에서 선언해야 합니다.

반대로, 내부 블록에서 외부 블록에 선언된 변수에는 접근할 수 있습니다. 내부 블록이 생성하는 영역은 외부 블록이 생성하는 영역에 포함되기 때문입니다.

루프 영역

아래 예제 코드에서 6행의 주석 처리를 해제하고 컴파일하면 에러가 발생합니다.

public class MethodExamples {
	public static void main(String[] args) {
		for (int i = 0; i < 5; i++) {
			System.out.println(i);
		}
		// System.out.println(i);
	}
}

for문 내에서 선언된 변수는 for문 내에서만 접근할 수 있습니다. 변수 i은 for문 외부에서는 접근할 수 없습니다.

만약에 for문 외부에 변수를 선언하면 아래와 같이 for문 외부에서 접근할 수 있습니다.

public class MethodExamples {
	public static void main(String[] args) {
		int i = 0;
		for (i = 0; i < 5; i++) {
			System.out.println(i);
		}
		System.out.println(i);
	}
}

메서드 영역

아래 예제 코드에서 4행의 주석 처리를 해제하고 컴파일하면 에러가 발생합니다.

public class MethodExamples {
	public static void main(String[] args) {
		System.out.println(add(3, 4));
		// System.out.println(a);
	}
	
	static int add(int a, int b) {
		return a + b;
	}
}

매개변수를 포함하여 메서드 내부에서 선언된 변수는 해당 메서드 내에서만 접근할 수 있습니다. 메서드 외부에서는 접근할 수 없습니다.

메서드 오버로딩

메서드 오버로딩을 이해하기 전에 메서드 시그니처에 대해서 먼저 알아보도록 하겠습니다.

메서드 시그니처(method signature)

자바는 메서드 시그니처를 통해 메서드를 구분합니다. 메서드 시그니처는 아래와 같으며, 반환형은 시그니처에 포함되지 않습니다.

  • 메서드의 이름
  • 매개변수의 개수, 타입

방금 메서드 시그니처를 통해 메서드를 구분한다고 했는데, 시그니처가 달라지면 다른 메서드로 인식할까요? 메서드의 이름이 같아도 매개변수의 개수가 다르다면요? 이런 궁금증을 싣고 메서드 오버로딩으로 넘어가보도록 하겠습니다.

메서드 오버로딩(method overloading)

메서드 오버로딩은 바로 메서드의 이름이 같지만 매개변수의 개수나 타입이 다른 메서드를 여러 개 정의할 수 있도록 하는 기능입니다. 메서드 오버로딩을 이용한 예제를 보도록 하겠습니다.

public class MethodExamples {
	public static void main(String[] args) {
		System.out.println("sum(4, 5): " + sum(4, 5));
		System.out.println("sum(10.4, 12.7): " + sum(10.4, 12.7));
		System.out.println("sum(1, 2, 3): " + sum(1, 2, 3));
	}
	
	static int sum(int a, int b) {
		return a + b;
	}
	
	static double sum(double a, double b) {
		return a + b;
	}
	
	static int sum(int a, int b, int c) {
		return a + b + c;
	}
}

코드를 살펴보면 3행에서 호출한 sum()은 sum(int, int)이므로 8~10행의 sum() 메서드가 호출되며, 4행에서 호출한 sum()은 sum(double, double)이므로 12~14행의 sum() 메서드가 호출됩니다. 마지막으로 5행에서 호출한 sum()은 sum(int, int, int)이므로 16~18행의 sum() 메서드가 호출됩니다. 이를 그림으로 확인하면 아래와 같습니다.

반환형만 다르면 컴파일러가 메서드를 구분할 수 없습니다. 위에서 말했듯이 반환형은 메서드 시그니처에 포함되지 않기 때문입니다.

static int sum(int a, int b) {
	return a + b;
}

// 컴파일 에러: 메서드 sum(int, int)이 중복됩니다.
static double sum(int a, int b) {
	return a + b;
}

'프로그래밍 관련 > 자바' 카테고리의 다른 글

15편. 생성자(Constructor)  (14) 2012.08.11
13편. 객체와 클래스(Objects and Classes)  (57) 2012.08.10
11편. 반복문 (2)  (11) 2012.08.08
10편. 반복문 (1)  (6) 2012.07.31
9편. 제어문 (2)  (20) 2012.07.30