클래스 내부 구성 요소 : 메서드
- -
메서드는 클래스의 기능에 해당하는 요소다. 예를 들어 사람 클래스라면 먹기, 잠자기, 공부하기, 자동차 클래스라면 전진하기, 후진하기, 회전하기 등이 메서드로 구성될 것이다. 먼저 메서드 정의의 문법적 구조를 살펴보자.
🍄메서드의 정의
자바 제어자 리턴(빤환) 타입 메서드명(입력매개변수) {
메서드 내용
}
예
public static int sum(int a, int b) {
// 메서드 내용
}
// public, static - 자바 제어자 int - 리턴(반환) 타입
리턴 타입은 메서드 종료 이후 변환(또는 반환)되는 값의 자료형을 의미한다. 메서드명은 변수명 선정 규칙과 동일하며 관례적으로 소문자로 시작한다. 이후 소괄호 안에는 입력 매개 변수가 들어오는데, 이는 메서드를 호출할 때 전달되는 값의 자료형과 전달받은 값을 저장할 지역 변수명을 정의한다. 마지막 중괄호 안에는 메서드의 내용이 들어가는데, 여기에 메서드가 수행해야 할 기능을 작성한다.
지금까지의 내용을 정리해 앞의 예제를 설명하면 '입력값으로 int형 2개의 값을 입력받아 처리하며, 메서드가 종료된 이후에 int값을 리턴한다.' 정도로 이야기할 수 있을 것이다. 리턴 타입이 void가 아닐 때 메서드 안에는 반드시 'return 리턴값'의 코드가 있어야 한다. 위 예제에서는 메서드 내용의 마지막에 'return 정숫값'의 코드가 반드시 있어야 오류가 발생하지 않을 것이다.
클래스 외부에서 메서드 호출하기
메서드도 클래스의 멤버이므로 객체 안에 존재할 것이고, 클래스 외부에서 메서드를 사용하려면 먼저 객체를 생성해야 할 것이다. 이어서 객체의 위치를 저장하고 있는 참조 변수를 이용해 메서드를 호출해야 한다. 다음 실습은 앞에서 알아본 4개의 메서드를 클래스 A에 구성하고 클래스 외부에서 클래스 A의 객체를 생성해 메서드를 호출하는 예다.
이 실습에서 알 수 있는 것처럼 리턴 타입이 void인 메서드의 경우 리턴되는 값이 없어 그대로 메서드만 호출(a.print())하지만, 리턴값이 있는 메서드는 일반적으로 리턴되는 값을 저장할 수 있는 변수를 선언해 대입(int k = a.data())한다. 물론 리턴값을 저장하지 않아도 (a.data()) 문법 오류는 발생하지 않는다. 다만 리턴값이 필요해 그 메서드를 호출햇을 것이므로 일반적이지는 않다.
입력매개변수가 있는 함수를 호출할 때는 해당 자료형의 값을 넘겨줘야 한다.double sum(int a, double b) 메서드에는 2개의 입력매개변수가 있으며, 첫 번째는 int, 두 번째는 double 자료형을 입력값으로 받는다. 따라서 이를 호출하려면 a.sum(3, 5.2)처럼 2개의 값을 각각의 자료형에 맞게 넘겨 줘야 한다. 그러면 sum()메서드의 지역 변수인 a값에는 3, b값에는 5.2가 입력돼 메서드가 종료될 때 값 8.2가 리턴되는 것이다. 입력매개변수를 넘겨주면 메서드 내부에서는 입력매개변수의 선언과 넘어온 값의 대입이 가장 먼저 실행된다. 즉, sum(3, 5.2)와 같이 호출하면 int a; double b; a = 3; b = 5.2; 코드가 가장 먼저 실행된 후 나머지 코드들이 순서대로 실행된다.
실습
// 클래스의 정의
class A {
// 리턴 타입 void, 입력매개변수 없음
void print() {
System.out.println("안녕");
}
// 리턴 타입 int, 입력매개변수 없음
int data() {
return 3;
}
// 리턴 타입 double, 입력매개변수 2개
double sum(int a, double b){
return a + b;
}
//리턴 타입 void, 내부에 리턴 포함(함수를 종료함)
void printMonth(int m) {
if(m < 0||m >12 ){
System.out.println("잘못된 입력");
return;
}
System.out.println(m+ "월입니다.");
}
}
public class jh {
public static void main(String[] args) {
// 객체 생성
A a = new A();
// 메서드 호출(멤버 활용)
a.print();
int k = a.data();
// a.data();
System.out.println(k);
double result = a.sum(3,5.2);
System.out.println(result);
a.printMonth(5);
a.printMonth(15);
}
}
클래스 내부에서 메서드 호출하기
이제 클래스 내부에서 메서드 간에 상호 호출할 때를 살펴보자. 클래스 내부에 있는 메서드끼리는 객체를 생성하지 않고 서로를 호출할 수 있다. 말 그대로 같은 멤버이기 때문이다. 필드 또한 멤버이므로 클래스 내부의 모든 메서드 안에서 객체를 생성하지 않고 자신이 속한 클래스의 필드를 사용할 수 있다. 다만 메서드 앞에 static이 붙어 있을 때는 static이 붙은 필드 또는 메서드만 호출할 수 있다. 이는 나중에 알아보기로 하고, 여기서는 '같은 멤버끼리는 클래스 내부에서 얼마든지 객체를 생성하지 않고 서로를 호출할 수 있다.'는 사실만 기억하자.
다음 예를 살펴보자. main() 메서드 내에서 같은 클래스에 포함된 메서드를 객체 생성 과정 없이 바로 호출해 사용하고 있다는 것을 알 수 있다.
public class jh {
public static void main(String[] args) {
// 같은 클래스 안에 있는 내부 메서드 호출
print();
int a = twice(3);
System.out.println(a);
double b = sum(a, 5.8);
System.out.println(b);
}
public static void print() {
System.out.println("안녕");
}
public static int twice(int k) {
return k * 2;
}
public static double sum(int m, double n){
return m + n;
}
}
입력 매개 변수가 배열인 메서드 호출하기
앞 예제에서 입력매개변수는 모두 기본 자료형이었다. 이제 다음과 같이 입력매개변수가 배열일 때를 살펴보자.
printArray() 메서드는 입력매개변수로 int[]자료형을 포함하고 있다. 따라서 이 메서드를 호출하기 위해서는 int[]객체를 생성해 입력매개변수로 넘겨 줘야 한다. 여기서는 2가지만 기억하자. 첫 번째는 호출할 때의 배열 데이터 입력 방법이다. 첫 번째처럼 new int[] {1, 2, 3}을 입력매개변수로 넘겨 주면 메서드에서는 다음 2줄의 코드가 가장 먼저 실행된다.
int a;
a = new int[] {1, 2, 3};
이 방법은 1차원 배열 객체를 생성하는 두 번째 방법이었다. 만약 세 번재 방법을 사용해 초깃값만 넘겨 준다면 다음과 같은 2줄이 실행되면서 오류가 발생한다.
int[] a;
a = {1, 2, 3};
초깃값만 넘겨줄 때는 선언과 동시에 값을 대입할 때(int[] a = {1, 2, 3})만 가능하기 때문이다.
기본 자료형 입력매개변수와 참조 자료형 입력매개변수의 차이
두 번째로 기억할 것은 배열과 같은 참조 자료형이 입력매개변수로 넘겨질 때 실제 객체가 전달되는 것이 아니라 객체의 위칫값이 전달된다는 것이다. 그 결과, 기본 자료형이 입력매개변수로 넘겨질 때와 다른 동작을 수행한다. 먼저 기본 자료형이 입력매개변수로 전달될 대를 살펴보자.
🦌기본 자료형 입력매개변수의 전달
기본 자료형일 때는 실제 값이 전달된다. 좀 더 정확하게 말하면, 기본 자료형의 값이 메서드의 지역 변수에 복사되는 것이다. 그럼 메모리상에서의 동작을 살펴보자.
위의 예에서 twice(3)의 호출로 넘겨진 값 3은 twice() 메서드의 지역 변수 a에 복사되고, a값을 두 배로 곱한 값을 a 값으로 저장한 후에 리턴한다. 즉, k1이 값은 6이다. 두 번째를 주의해서 봐야 하는데, main() 함수 안의 a 값을 twice() 메서드의 입력으로 넘겨줬다. 그러면 twice()메서드에서는 int a(twice()메서드의 지역 변수) =a(main() 메서드의 지역 변수)를 가장 먼저 실행할 것이다. 등호(=)는 스택 메모리를 복사하라는 말이므로 main() 메서드의 지역 변수 a의 스택 메모리값이 지역 변수 a로 복사되는 것이다. 이후 twice()메서드는 자신의 a 값을 2배로 곱한 후 변수 a값에 넣었으므로 twice() 메서드의 a 값에는 6이 저장된다.
이때 twice() 메서드의 호출이 끝나고 다시 main() 메서드로 돌아오면 main() 메서드의 a 값은 얼마일까? 여전히 3일 것이다. twice() 메서드는 단 한 번도 main() 함수의 a 값을 건드린 적이 없기 때문이다. 심지어 twice() 메서드의 실행을 완료하고 main()함수로 돌아온 시점에는 메모리에서 twice() 프레임 자체가 날아간 이후이므로 twice() 메서드의 지역 변수 a는 메모리상에 존재하지도 않는다. 이렇게 기본 자료형을 입력매개변수로 전달하면 전달받은 메서드는 값을 복사해 사용한다.
실습
public class jh {
public static void main(String[] args) {
int a = 3;
int result1 = twice(3);
System.out.println(result1);
int result2 = twice(a);
System.out.println(result2);
System.out.println(a);
}
public static int twice(int a) {
a = a * 2;
return a;
}
}
반면 참조 자료형을 입력매개변수로 넘겼을 때를 살펴보자. 이때도 입력매개변수로 넘겨진 변수의 스택 메모리값이 복사돼 사용되는 것은 동일하지만 참조 자료형은 스택 메모리에 객체의 참좃값(위칫값)을 저장하고 있으므로 실제 객체가 아닌 객체의 참좃값이 전달돼 복사된다. 그러다보니 호출한 메서드와 호출된 메서드에서 모두 동일한 객체를 쳐다보고 있는 상황이 연출된다. 그래서 호출된 메서드에서 객체의 값을 변경한 후 호출한 메서드로 돌아오면 값이 바뀌게 된다.
🦌참조 자료형 입력매개변수의 전달
위 예제를 실행하는 과정에서 메모리에 생성되는 데이터의 모양은 다음과 같다.
위 두 예제의 메모리를 쳐다보고 있으면 이 둘 사이의 차이점을 자연스럽게 이해할 수 있을 것이다.
실습
public class jh {
public static void main(String[] args) {
int[] array = new int[] {1, 2, 3};
modifyData(array);
printArray(array);
}
public static void modifyData(int[] a){
a[0] = 4;
a[1] = 5;
a[2] = 6;
}
public static void printArray(int[] a){
System.out.println(Arrays.toString(a));
}
}
'개인공부 > Java' 카테고리의 다른 글
내부 객체 참조 변수명인 this (0) | 2022.07.18 |
---|---|
메서드 오버로딩 (0) | 2022.07.18 |
클래스의 내부 구성 요소 : 변수 (0) | 2022.07.18 |
클래스와 객체 (0) | 2022.07.18 |
참조 자료형 String (0) | 2022.07.18 |
소중한 공감 감사합니다