본문 바로가기
Java

자바 메소드

by 승환파크 2023. 6. 23.

메소드 선언은 선언부와 실행 블록으로 구성된다. 메소드 선언부를 메소드 시그너처 라고 하며, 선언부와 실행 블록에는 다음 요소를 포함해야한다.

  • 리턴 타입 : 메소드가 리턴하는 결과의 타입을 표시한다.
  • 메소드 이름 : 메소드의 기능이 드러나도록 식별자 규칙에 맞게 이름을 지어준다.
  • 매개 변수 선언 : 메소드를 실행할 때 필요한 데이터를 받기 위한 변수를 선언한다.
  • 메소드 실행 블록 : 실행할 코드를 작성한다.
리턴타입 메소드이름 ([매개 변수 선언, ...]) { <-- 메소드 실행 블록
	실행할 코드를 작성하는 곳
}

 

 

메소드 선언

메소드 선언은 선언부(리턴 타입, 메소드 이름, 매개 변수 선언)와 실행 블록으로 구성된다.

 

리턴 타입

리턴 타입은 리턴값의 타입을 말한다. 리턴값이란 메소드를 실행한 후의 결과값을 말한다. 메소드는 리턴값이 있을 수도 있고 없을 수도 있으나 리턴값이 있을 경우 리턴 타입이 선언부에 명시되어야 한다.

 

예를 들어 전자계산기 객체에서 전원을 켜는 powerOn() 메소드와 두 수를 나누는 기능은 divide()메소드가 있다고 가정을 해보면 powerOn() 메소드는 전원만 키는 기능으로 리턴값이 없다. 하지만 divide() 메소드는 나눗셈 결과를 리턴해야한다. 리턴값이 없는 메소드는 리턴 타입에 void 로 기술하며, 리턴값이 있는 메소드는 리턴값의 타입을 기술한다. divide() 메소드의 결과가 double 값이라면 리턴 타입으로 double을 기술해야 한다.

public void powerOn(){
	...
}

public double divide(int x, int y){
	double result = x / y;
    return result;
}

 

리턴값이 있느냐 없느냐에 따라 메소드를 호출하는 방법이 다르다. 위의 두 메소드는 다음과 같이 호출할 수 있다.

powerOn();
double result = divide(10, 20);

 

powerOn()메소드는 리턴값이 없기 때문에 변수에 저장할 내용이 없다. 단순히 메소드만 호출하면 된다. 하지만 divide() 메소드는 10을 20으로 나눈 후 0.5를 리턴하므로 이것을 저장할 변수가 있어야 한다. 리턴값을 받기 위해 변수는 divide() 메소드의 리턴 타입인 double 타입으로 선언되어야 한다. 만약 result 변수를 int 타입으로 선언하게 되면 double 값을 저장할 수 없기 때문에 컴파일 에러가 발생한다.

 

리턴 타입이 있다고 해서 반드시 리턴값을 변수에 저장할 필요는 없다. 리턴값이 중요하지 않고, 메소드 실행이 중요할 경우에는 아래와 같이 변수를 선언하지 않고 메소드를 호출할 수 있다.

divide(10, 20);

 

메소드 이름

메소드 이름은 자바 식별자 규칙에 맞게 작성하면 되는데, 다음 사항에 주의해야 한다.

  • 숫자로 시작하면 안 되고, $와 _를 제외한 특수 문자를 사용하면 안된다.
  • 관례적으로 메소드 이름은 소문자로 작성한다.
  • 서로 다른 단어가 혼합된 이름이라면 뒤이어 오는 단어의 첫 글자는 대문자로 작성한다.(카멜식 케이스)

아래에 잘 작성된 메소드 이름을 볼 수 있다. 메소드 이름은 이 메소드가 어떤 기능을 수행하는지 쉽게 알 수 있도록 기능 이름을 작성해야 한다. 이름의 길이는 프로그램 실행과는 무관하니, 너무 짧게 지어주지 않는 것이 좋다.

void run(...){
	...
}

void startEngine(...){
	...
}

String getName(...){
	...
}

int[] getScores(...){
	...
}

 

매개 변수 선언

매개 변수는 메소드가 실행할 때 필요한 데이터를 외부로부터 받기 위해 사용된다. 메소드에서 매개 변수가 필요한 경우가 있고 필요 없는 경우가 있다.

 

예를 들어 powerOn() 메소드는 그냥 전원면 켜면 그만이지만, divide() 메소드는 나눗셈할 두 수가 필요하다. 따라서 powerOn() 메소드는 매개 변수가 필요하지 않고, divide() 메소드는 매개 변수가 2개 필요하다.

 

매개 변수의 개수를 모를 경우

메소드의 매개 변수는 개수가 이미 정해져 있는 것이 일반적이지만, 어떤 상황에서는 메소드를 선언할 때 매개 변수의 개수를 알 수 없는 경우도 있다. 예를 들어 여러 개의 수를 모두 합산하는 메소드를 선언해야 한다면 몇 개의 매개 변수가 입력될지 알 수 없기 때문에 매개 변수의 개수를 결정할 수 없다.

 

해결책은 아래와 같이 매개 변수를 배열 타입으로 선언하는 것이다.

int sum1(int[] values){
	...
}

 

sum1() 메소드를 호출할 때 배열을 넘겨줌으로써 배열의 항목 값들을 모두 전달할 수 있다. 배열의 항목 수는 호출할 때 결정된다.

int[] values = {1, 2, 3};
int result = sum1(values);
int result = sum(new int[] {1, 2, 3, 4, 5});

 

매개 변수를 배열 타입으로 선언하면 메소드를 호출하기 전에 배열을 생성해야 한느 불편한 점이 있다. 그래서 배열을 생성하지 않고 값의 목록만 넘겨주는 방법도 있다. 아래와 같이 sum2() 매소드의 매개 변수를 ...를 사용해서 선언하게 되면 메소드 호출 시 넘겨준 값의 수에 따라 자동으로 배열이 생성되고 매개값으로 사용된다.

int sum2(int ... values){
	...
}

 

...로 선언된 매개 변수의 값은 아래와 같이 메소드 호출시 쉼표로 나열해주면 된다.

int result = sum2(1, 2, 3);

 

...로 선언된 매개 변수는 배열 타입이므로 아래와 같이 배열을 직접 매개값으로 사용해도 된다.

int[] values = (1, 2, 3);
int result = sum2(values);
int result = sum2(new int[] {1, 2, 3});

 

 

리턴문

리턴값이 있는 메소드

메소드 선언에 리턴 타입이 있는 메소드는 반드시 리턴문을 사용해서 리턴값을 지정해야 한다. 만약 return문이 없다면 컴파일 에러가 발생하고, return문이 실행되면 메소드는 반드시 종료한다.

return 리턴값;

 

return문의 리턴값은 리턴 타입이나 리턴 타입으로 변환될 수 있어야 한다. 예를 들어 리턴 타입이 int인 plus() 메소드에서는 byte, short, int 값이 리턴되어도 상관 없다. byte 와 short는 int 로 자동 타입 변환되어 리턴되기 때문이다.

 

리턴값이 없는 메소드 : void

리턴값이 없는 메소드는 리턴 타입으로 void를 사용한다. 그런데 void로 선언된 메소드에서도 return문을 사용할 수 있다. 이것은 리턴값을 지정하는 것이 아니라 메소드 실행을 강제로 종료시키는 역할을 한다.

return;

 

 

 

메소드 호출

메솓는 클래스 내, 외부의 호출에 의해 실행된다. 클래스 내부의 다른 메소드에서 호출할 경우에는 단순한 메소드 이름으로 호출하면 되지만, 클래스 외부에서 호출할 경우에는 우선 클래스로부터 객체를 생성한 뒤 참조 변수를 이용해서 메소드를 호출해야 한다. 객체가 존재햐야 메소드도 존재하기 때문이다.

 

객체 내부에서 호출

클래스 내부에서 다른 메소드를 호출할 경우에는 아래와 같은 형태로 작성하면 된다. 메소드가 매개 변수를 가지고 있을 때에는 매개 변수의 타입과 수에 맞게 매개값을 제공한다.

메소드(매개값, ...);

 

예를 들어 method2() 메소드에서 method1() 메소드를 호출하려면 아래와 같이 작성한다.

호출할 때 method1("홍길동", 100)이 호출되면 매개값인 "홍길동"은 p1 매개 변수에 대입되고 100은 p2 매개 변수에 대입된다. 이후 메소드 실행 과정에서 p1 과 p2 변수를 이용한다.

public class ClassName{
	void method1(String p1, int p2){
    	...
    }
    
    void method2(){
    	method1("홍길동", 100);
    }
}

 

메소드가 리턴값이 없거나, 있어도 받고 싶지 않을 경우 위와 같이 모두 호출이 가능하다. 리턴값이 있는 메소드를 호출하고 리턴값을 받고 싶다면 아래와 같이 변수를 선언하고 리턴값을 대입한다.

타입 변수 = 메소드(매개값1, ...);

 

이 때 변수 타입은 리턴 타입과 동일하거나, 자동 타입 변환이 될 수 있어야 한다는 점에 주의해야 한다. 예를 들어 int는 double 타입으로 자동 변환되기 때문에 int 리턴값은 double 타입 변수에 대입할 수 있다.

 

객체 외부에서 호출

외부 클래스에서 메소드를 호출하려면 우선 아래와 같이 클래스로부터 객체를 생성해야 한다. 메소드는 객체에 소속된 멤버이므로 객체가 존재하지 않으면 메소드도 존재하지 않기 때문이다.

클래스 참조변수 = new 클래스(매개값, ...);

 

객체가 생성되었다면 참조 변수와 함께 도트(.) 연산자를 사용해서 메소드를 호출할 수 있다. 도트 연산자는 객체 접근 연산자로 객체가 가지고 있는 필드나 메소드에 접근할 때 사용된다.

참조변수.메소드(매개값1, ...); // 리턴값이 없거나, 있어도 리턴값을 받지 않을 경우
타입 변수 = 참조변수.메소드(매개값1, ...) // 리턴값이 있고, 리턴값을 받고 싶은 경우

 

 

메소드 오버로딩

클래스 내에 같은 이름의 메소드를 여러 개 선언하는 것을 메소드 오버로딩 이라고 한다. 오버로딩의 사전적 의미는 많이 싣는것을 뜻한다. 하나의 메소드 이름으로 여러 기능을 담는다 하여 붙여진 이름이다. 메소드 오버로딩의 조건은 매개 변수의 타입, 개수, 순서 중 하나가 달라야 한다는 점이다.

class 클래스{
	리턴 타입 메소드이름(타입 변수, ...){
		...
	}
    
    리턴 타입 메소드이름(타입 변수, ...){
		...
	}
}
// 리턴 타입은 상관없음
// 메소드 이름은 같아야함
// 매개 변수의 타입, 개수, 순서가 달라야 함

 

메소드 오버로딩이 필요한 이유는 매개값을 다양하게 받아 처리할 수 있도록 하기 위해서이다. 예를 들어 아래와 같이 plus() 메소드가 있다고 가정을 했을 때

int plus(int x, int y){
	int result = x + y;
    return result;
}

plus() 메소드를 호출하기 위해서는 2개의 int 매개값이 필요하다. 하지만 int 타입이 아니라 double 타입의 값을 덧셈하기 위해서는 plus() 함수를 호출할 수 없다. 해결 방법은 매개 변수가 double 타입으로 선언된 plus() 함수를 하나 더 선언하는 것이다.

double plus(double x, double y){
	double result = x + y;
    return result;
}

오버로딩 된 메소드를 호출할 경우 JVM은 매개값의 타입을 보고 메소드를 선택한다.

 

예를 들어 아래와 같이 plus() 메소드를 호출하면 매개값이 정수이므로 plus(int x, int y) 가 실행된다.

plus(10, 20);

 

그리고 아래와 같이 plus() 메소드를 호출하면 매개값이 실수이므로 plus(double x, double y) 가 실행된다.

plus(10.5, 20.3);

 

이 때 만약 아래와 같은 코드를 작성해서 실행하면 어떻게 되는지 알아보자

int x = 10;
double y = 20.3;
plus(x, y);

첫 번째 매개 변수가 int 타입이고 두 번째 매개 변수가 double 타입인 plus() 메소드가 없기 때문에 컴파일 에러가 날 것 같지만 plus(double x, double y) 메소드가 실행된다. JVM은 일차적으로 매개 변수의 타입을 보지만, 매개 변수의 타입이 일치하지 않을 경우 자동 타입 변환이 가능한지를 검사한다. 첫 번째 매개변수인 int는 double 타입으로 변환이 가능하므로 최종적으로 plus(double x, double y) 메소드가 선택된다.

 

메소드를 오버로딩 할 때 주의할 점은 매개 변수의 타입과 개수, 순서가 똑같은 경우 매개 변수의 이름이 다르다고 해서 이것을 메소드 오버로딩이라고 하지 않는다는 것이다. 또한 리턴 타입만 다르고 매개 변수가 동일하다면 이것도 오버로딩이라고 하지 않는다. 왜냐하면 리턴 타입은 JVM이 메소드를 선택할 때 아무런 도움을 주지 못하기 때문이다.

'Java' 카테고리의 다른 글

자바 패키지와 접근 제한자  (0) 2023.06.26
자바 인스턴스 멤버와 정적 멤버  (0) 2023.06.23
자바 생성자  (0) 2023.06.22
자바 필드  (0) 2023.06.22
자바 클래스  (0) 2023.06.22