자바 매개변수와 메서드와 재귀 호출에 대해 알아보자
2025. 2. 5. 13:00ㆍJAVA
728x90
반응형
안녕하세요. 진득코딩입니다.
저번 시간에 매개변수와 메서드에 대해서 알아보았습니다.
매개변수와 메서드를 사용할 때는 여러 규칙이 존재합니다.
이번 시간에는 매개변수와 메서드를 사용할 때의 여러 규칙과 자기 자신을 호출하는 재귀 호출에 대해 알아보도록 하겠습니다.
기본형 매개변수와 참조형 매개변수
- 자바에서는 메서드를 호출할 때 매개변수로 지정한 값을 메서드의 매개변수에 복사해서 넘겨줍니다.
- 매개변수의 타입이 기본형(primitive type)일 때는 기본형 값이 복사되지만, 참조형(reference type)이면 인스턴스 주소가 복사됩니다.
- 메서드의 매개변수를 기본형을 선언하면 단순히 저장된 값을 얻지만, 참조형으로 선언하면 값이 저장된 곳의 주소를 알 수 있기 때문에 값을 읽어 오는 것은 물론 값을 변경하는 것도 가능합니다.
기본형 매개변수 : 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수 : 변수의 값을 읽고 변경할 수 있다.(read & write)
- change메서드에서 main메서드로부터 넘겨받은 d.x의 값을 1000으로 변경했는데도 main메서드에서는 d.x의 값이 그대로입니다.
- 이는 'd.x'의 값이 변경되 것이 아니라, change메서드의 매개변수 x의 값이 변경된 것이기 때문입니다.
- 즉, 원본이 아닌 복사본이 변경된 것이라 원본에는 아무런 영향을 미치지 못합니다.
- change메서드를 호출한 후에 d.x의 값이 변경되었습니다.
- change메서드의 매개변수가 참조형이라서 값이 아니라 '값이 저장된 주소'를 change메서드에게 넘겨주었기 때문에 값을 읽어오는 것뿐만 아니라 변경하는 것도 가능합니다.
- change메서드의 매개변수를 참조형으로 선언했기 때문에, x의 값이 아닌 주소가 매개변수 d에 복사되었습니다.
- 이제 main메서드의 참조변수 d와 change메서드의 참조변수 d는 같은 객체를 가리키게 됩니다.
- 그래서 매개변수 d로 x의 값을 읽는 것과 변경하는 것이 모두 가능합니다.
- Data클래스의 인스턴스 대신 길이가 1인 배열 x를 사용하도록 코드를 작성하였습니다.
- 배열도 객체와 같이 참조변수를 통해 데이터가 저장된 공간에 접근합니다.
- 그래서 변수 x도 int배열타입의 참조변수이기 때문에 같은 결과를 얻습니다.
- 임시적으로 간단히 처리할 때는 별도의 클래스를 선언하는 것보다 이처럼 배열을 이용할 수도 있습니다.
- 메서드로 배열을 다루는 여러 가지 방법을 보여주는 예제입니다.
- 매개변수의 타입이 배열이니까, 참조형 매개변수입니다.
- 그래서 sortArr메서드에서 정렬한 것이 원래의 배열에 영향을 미칩니다.
- 이 예제는 반환값이 있는 메서드를 반환값이 없는 메서드로 바꾸는 방법을 보여줍니다.
- 참조형 매개변수를 활용하면 반환값이 없어도 메서드의 실행결과를 얻어 올 수 있습니다.
참조형 반환타입
- 매개변수뿐만 아니라 반환타입도 참조형이 될 수 있습니다.
- 모든 참조형 타입의 값은 '객체의 주소'이므로 그저 정수값이 반환되는 것일 뿐 특별할 것은 없습니다.
- copy메서드는 새로운 객체를 생성한 다음에, 매개변수로 넘겨받은 객체에 저장된 값을 복사해서 반환합니다.
- 반환하는 값이 Data객체의 주소이므로 반환 타입이 'Data'입니다.
- copy메서드 내에서 생성한 객체를 main메서드에서 사용할 수 있으려면, 이렇게 새로운 객체의 주소를 반환해줘야 합니다.
- 그렇지 않으면, copy메서드가 종료되면서 새로운 객체의 참조가 사라지기 때문에 더 이상 이 객체를 사용할 방법이 없습니다.
반환타입이 '참조형'이라는 것은 메서드가 '객체의 주소'를 반환한다는 것을 의미합니다.
재귀호출(recursive call)
- 재귀호출(recursive call)은 메서드 내부에서 메서드 자신을 다시 호출하는 것을 의미합니다.
- 재귀 메서드는 재귀호출을 하는 메서드를 의미합니다.
void method() {
method(); //재귀호출. 메서드 자신을 호출한다.
}
- 호출된 메서드는 '값에 의한 호출(call by value)'을 통해, 원래의 값이 아닌 복사된 값으로 작업하기 때문에 호출한 메서드와 관계없이 독립적인 작업수행이 가능합니다.
- 그런데 위 코드와 같이 오로지 재귀호출뿐이면, 무한히 자기 자신을 호출하기 때문에 무한 반복에 빠지게 됩니다.
- 그래서 재귀호출은 조건문이 필수적으로 필요합니다.
- 위 코드는 매개변수 n을 1씩 감소시켜가면서 재귀호출을 하다가 n의 값이 0이 되면 재귀 호출을 중단하게 됩니다.
- 메서드를 후출하는 것은 반복문보다 몇 가지 과정, 예를 들면 매개변수 복사와 종료 후 복귀할 주소저장 등, 이 추가로 필요하기 때문에 반복문보다 재귀호출이 수행시간이 더 오래 걸립니다.
- 그럼에도 불구하고 반복문 대신 재귀호출을 사용하는 이유는 재귀호출이 주는 논리적 간결함 때문입니다.
- 효율적이라도 알아보기 힘들게 작성하는 것보다 다소 비효율적이더라도 알아보기 쉽게 작성하는 것이 논리적 오류가 발생할 확률도 줄어들고 나중에 수정하기도 좋습니다.
- 재귀호출은 비효율적이므로 재귀호출에 드는 비용보다 재귀호출의 간결함이 주는 이득이 충분히 큰 경우에만 사용해야 합니다.
- 위 예제는 팩토리얼을 계산하는 메서드를 구현하고 테스트하는 예제입니다.
- factorial메서드가 static메서드이므로 인스턴스를 생성하지 않고 직접 호출할 수 있습니다.
- main메서드와 같은 클래스에 있기 때문에 static메서드를 호출할 때 클래스이름을 생략하는 것이 가능합니다.
- 메서드를 작성할 때는 어떤 값이 들어와도 에러 없이 처리되는 견고한 코드를 작성해야 합니다.
- 그래서 '매개변수의 유효성검사'가 중요합니다.
- 매개변수의 유효성을 검사하는 코드를 추가해서 메서드 factorial의 매개변수 n이 음수거나 20보다 크면 -1을 반환하도록 하였습니다.
- main메서드 역시 자기 자신을 호출하는 것이 가능하며 아무런 조건도 없이 계속해서 자기 자신을 다시 호출하기 때문에 무한 호출에 빠지게 됩니다.
- x^1부터 x^n까지의 합을 구하는 예제입니다.
- 재귀호출을 사용하여 x^n을 구하는 power()를 작성하였습니다.
클래스 메서드(static메서드)와 인스턴스 메서드
- 메서드 앞에 static이 붙어 있으면 클래스메서드이고 붙어 있지 않으면 인스턴스 메서드입니다.
- 클래스 메서드도 클래스변수처럼, 객체를 생성하지 않고도 '클래스이름.메서드이름(매개변수)'와 같은 식으로 호출이 가능합니다.
- 반면에 인스턴스 메서드는 반드시 객체를 생성해야만 호출할 수 있습니다.
- 인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드입니다.
- 반면에 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static메서드)로 정의합니다.
- 클래스를 설계할 때, 맴버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙입니다.
- 생성된 각 인스턴스는 서로 독립적이기 때문에 각 인스턴스의 변수 (iv)는 서로 다른 값을 유지합니다
- 그러나 모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 합니다. - 클래스 변수(static 변수)는 인스턴스를 생성하지 않아도 사용할 수 있습니다.
- static이 붙은 변수(클래스변수)는 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기 때문입니다. - 클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없습니다.
- 인스턴스변수는 인스턴스가 반드시 존재해야만 사용할 수 있는데, 클래스메서드(static이 붙은 메서드)는 인스턴스 생성 없이 호출 가능하므로 클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있습니다.
- 그래서 클래스 메서드에서 인스턴스변수의 사용을 금지합니다.
- 반면에 인스턴스변수나 인스턴스메서드에서는 static이 붙은 맴버들을 사용하는 것이 언제나 가능합니다. - 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려합니다.
- 메서드의 작업 내용 중에서 인스턴스 변수를 필요로 한다면, static을 붙일 수 없습니다.
- 반대로 인스턴스변수를 필요로 하지 않는다면 static을 붙입니다.
- 메서드 호출 시간이 짧아지므로 성능이 향상됩니다.
- static을 안 붙인 메서드(인스턴스메서드)는 실행 시 호출되어야 할 메서드를 찾는 과정이 추가적으로 필요하기 때문에 시간이 더 걸립니다.
- 클래스의 맴버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 것이 있는지 살펴보고 있으면, static을 붙여줍니다.
- 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려합니다.
- 인스턴스메서드인 add(), subtract(), multiply(), divide()는 인스턴스변수인 a와 b만으로도 충분히 작업이 가능하기 때문에, 매개변수를 필요로 하지 않으므로 괄호()에 매개변수를 선언하지 않았습니다.
- 반면에 add(long a, long b), stract(long a, long b) 등은 인스턴스변수 없이 매개변수만으로 작업을 수행하기 때문에 static을 붙여서 클래스메서드로 선언하였습니다.
클래스 맴버와 인스턴스 맴버 간의 참조와 호출
- 같은 클래스에 속한 맴버들 간에는 별도의 인스턴스를 생성하지 않고도 서로 참조 또는 호출이 가능합니다.
- 단, 클래스맴버가 인스턴스 맴버를 참조 또는 호출하고자 하는 경우에는 인스턴스를 생성해야 합니다.
- 그 이유는 인스턴스 맴버가 존재하는 시점에 클래스 맴버는 항상 존재하지만, 클래스 맴버가 존재하는 시점에 인스턴스 맴버가 존재하지 않을 수도 있기 때문입니다.
- 같은 클래스 내의 메서드는 서로 객체의 생성이나 참조변수 없이 직접 호출이 가능하지만 static메서드는 인스턴스 메서드를 호출할 수 없습니다.
- 인스턴스메서드는 인스턴스변수를 사용할 수 있지만, static메서드는 인스턴스변수를 사용할 수 없습니다.
- 인스턴스맴버는 반드시 객체를 생성한 후에만 참조 또는 호출이 가능하기 때문에 클래스 맴버가 인스턴스 맴버를 참조, 호출하기 위해서는 객체를 생성해야 합니다.
- 하지만 인스턴스 맴버간의 호출에는 아무런 문제가 없습니다.
- 하나의 인스턴스 맴버가 존재한다는 것은 인스턴스가 이미 생성되었다는 것을 의미하며, 즉 다른 인스턴스 맴버들도 모두 존재하기 때문입니다.
이번 시간에는 매개변수와 메서드를 사용하는 방법에 대해서 살펴보았습니다.
특히나 인스턴스 맴버와 클래스 맴버의 차이를 살펴보고 각각의 맴버들을 어떤 식으로 사용하는지 살펴보았습니다.
저번 시간에 배운 JVM의 메모리 구조와 함께 맴버들을 어떤 식으로 사용하는지에 대해 생각해 보는 시간을 가지면 좋을 것 같습니다.
이번 포스팅은 여기까지입니다.
궁금하신 사항이나 문의하실 사항은 댓글에 남겨주시면 열심히 답글 달도록 하겠습니다.
끝까지 봐주셔서 감사합니다.😊
728x90
반응형
LIST
'JAVA' 카테고리의 다른 글
자바 생성자와 변수의 초기화에 대해 알아보자 (2) | 2025.02.07 |
---|---|
자바 오버로딩(overloading)에 대해 알아보자 (0) | 2025.02.06 |
자바 메서드와 JVM의 메모리 구조에 대해 알아보자 (0) | 2025.02.04 |
객체지향언어 자바의 객체와 클래스를 알아보자 (0) | 2025.02.03 |
자바 다차원 배열과 가변 배열에 대해 알아보자 (2) | 2025.01.31 |