클래스의 기능을 구현한 것. 함수와 거의 같고, 클래스에 속한 함수를 메서드라고 부른다.
기능 하나에 이름 하나
함수는 하나의 기능을 수행하는 코드 묶음이다. 미리 구현해두고 필요할 때마다 호출한다. 같은 코드를 여러 번 쓰지 않아도 되고, 기능 단위로 나뉘어 읽기 쉬워지고, 고칠 곳이 한 군데로 모인다. 오류가 난 기능만 찾아 고치면 되니 디버깅도 편해진다. 하나의 함수에 여러 기능이 섞이면 이 이점이 전부 사라지므로 이름에 맞는 기능 하나만 담는다.
클래스에 종속된 함수가 메서드인데, 인터페이스에 static 메서드가 추가되면서 종속되지 않은 상태로도 쓸 수 있게 되어 다시 함수라고 부르는 경우도 생겼다. 함수형 인터페이스
매개변수와 반환값
[접근제한자] [static] 리턴타입 메서드이름([매개변수, ...]) {
실행문
}들어가는 것이 매개변수이고 나오는 것이 반환값이다. 매개변수(parameter)는 정의할 때 적는 변수, 인자(argument)는 부를 때 넘기는 실제 값이다. 돌려줄 값이 없으면 반환형 자리에 void를 쓴다. 메서드 이름은 소문자로 시작하는 것이 관행이다.
호출 스택에 쌓이는 프레임
메서드를 부르면 호출 스택에 스택 프레임이 하나 쌓이고 그 안에 지역 변수와 매개변수가 들어간다. 메서드가 끝나면 프레임이 통째로 빠진다. 지역 변수를 메서드 밖에서 쓸 수 없는 이유이고, 재귀가 깊어지면 스택 오버플로가 나는 이유이기도 하다. 어느 메모리 영역에 무엇이 놓이는지는 메모리 구조에 정리해두었다.
같은 메서드를 동시에 열 번 불러도 각 호출의 지역 변수는 저마다 다른 프레임에 있어 섞이지 않는다. 문제는 메서드가 클래스에 선언된 변수를 건드리는 순간부터 시작된다.
오버로딩
같은 이름의 메서드를 매개변수만 달리해 여러 개 두는 것이 오버로딩이다.
void print(int a) { }
void print(String s) { }
void print(int a, int b) { }매개변수의 타입, 개수, 순서 가운데 하나라도 달라야 한다. 반환 타입만 다른 것은 오버로딩이 아니다. 부르는 쪽만 보고는 어느 것인지 정할 수 없기 때문이다. 어느 것이 불릴지는 컴파일 시점에 정해지고, 실행 시점에 정해지는 오버라이딩과 이 대목에서 갈린다.
PrintStream이 println()만 열 개 가까이 선언해둔 것이 이 문법의 쓰임이다. 숫자를 출력하든 문자를 출력하든 이름을 다르게 지을 이유가 없다. 만드는 쪽이 어렵게 만들고 쓰는 쪽이 쉽게 쓰게 하는 것이다.
가변인자
개수가 정해지지 않은 인자를 받는 문법도 있다.
public static int sum(int... args) { }sum(5, 10)도 sum(3, 1, 2, 3, 4, 1)도 이 메서드 하나가 받는다. 안에서는 배열이라 args.length로 개수를 알 수 있다.
참고
원본은 가변인자를 개수가 정해지지 않은 인자를 받는 문법으로만 다룬다. 자바 언어 명세는 자리에 제약을 둔다. “메서드나 생성자에 가변인자 매개변수는 최대 하나만 허용된다. 가변인자 매개변수가 매개변수 목록의 마지막이 아닌 자리에 나타나면 컴파일 오류다.” JLS SE 21 §8.4.1