해당 내용은 인프런에 있는 [김영한의 자바 입문] 강의를 보고 참고하여 정리한 글이다.
혹시 문제가 된다면 꼭 알려주시길 바랍니도...😢
9. 메서드
메서드 호출과 값 전달1
***자바에서 아주 중요한 대원칙 中 하나(아주 중요하다고 함!!!!!!!)***
자바는 항상 변수의 값을 복사해서 대입함
이 대원칙은 반드시 이해해야 함 / 그렇다면 아무리 복잡한 상황에도 코드를 단순하게 이해할 수 있을 것임
변수와 값 복사
package method;
public class MethodValue0 {
public static void main(String[] args) {
int num1 = 5;
int num2 = num1;
num2 = 10;
System.out.println("num1 = " + num1);
System.out.println("num2 = " + num2);
}
}
//실행 결과
num1 = 5
num2 = 10
값을 복사해서 대입한다는 부분
int num2 = num1;
- 이 부분은 num1에 있는 값 5를 복사해서 num2에 넣은 것임
- 복사한다고 표현한 이유는 num1의 값을 읽어도, num1에 있는 기존 값은 유지되고, 새로운 값이 num2에 들어갔기 때문 // 마치 num1의 값이 num2에 복사가 된 것 처럼
- num1이라는 변수 자체가 num2에 들어가는 것이 아님, num1에 들어있는 값을 읽고 복사해서 num2에 넣은 것
- 간단하게 num1에 있는 값을 num2에 대입한다고 표현함 하지만 실제로 그 값을 복사해서 대입하는 것임
당연한 소리 아닌가,,,? 싶었음// 다음 예제를 보자
예제 MethodValue1 )
package method;
public class MethodValue1 {
public static void main(String[] args) {
int num1 = 5;
System.out.println("1. changeNumber 호출 전, num1: " + num1);
changeNumber(num1);
System.out.println("4. changeNumber 호출 후, num1: " + num1);
}
public static void changeNumber(int num2) {
System.out.println("2. changeNumber 변경 전, num2: " + num2);
num2 = num2 * 2;
System.out.println("3. changeNumber 변경 후, num2: " + num2);
}
}
마지막 4번 출력의 결과가 10이라고 생각했다면 대원칙을 떠올려라
//실행결과
1. changeNumber 호출 전, num1: 5
2. changeNumber 변경 전, num2: 5
3. changeNumber 변경 후, num2: 10
4. changeNumber 호출 후, num1: 5
대원칙을 따라간다면 문제를 정확하게 풀 수 있음
자바는 항상 변수의 값을 복사해서 대입함
실행 과정 그림
changeNumber(num1)호출 시점
- num1의 값 5를 읽고 복사해서 num2에 전달 => 이 부분이 핵심
changeNumber 메서드 실행 중
- num2의 변경은 num1에 영향을 주지 않음 / 왜냐하면 앞서 값을 복사해서 전달했기 때문
실행 과정 코드
changeNumber(num1); //changeNumber를 호출한다. num1(5)
changeNumber(5); //num1의 값을 읽는다.
void changeNumber(int num2 = num1) //num1의 값 5가 num2에 복사된다. 결과: num1(5), num2(5)
num2 = num2 * 2; //num2에 2를 곱한다. 결과: num1(5), num2(5)
num2 = 5 * 2; //num2의 값을 읽어서 2를 곱한다. 결과: num1(5), num2(10)
num2 = 10; //num2에 계산 결과인 값 10을 대입한다. 결과: num1(5), num2(10)
num2를 출력한다: num2의 값인 10이 출력된다.
num1을 출력한다: num1의 값인 5가 출력된다.
결과적으로 매개변수 num2의 값만 10으로 변경되고 num1의 값은 변경되지 않고 기존 값인 5로 유지됨
자바는 항상 값을 복사해서 전달하기 때문에 num2의 값을 바꾸더라도 num1에는 영향을 주지 않음
메서드 호출과 값 전달2
메서드 호출과 이름이 같은 변수
같은 문제를 호출자의 변수 이름과 매개변수의 이름을 같게 해서 한번 더 풀어봄
예제 MethodValue2 )
package method;
public class MethodValue2 {
public static void main(String[] args) {
int number = 5;
System.out.println("1. changeNumber 호출 전, number: " + number);
changeNumber(number);
System.out.println("4. changeNumber 호출 후, number: " + number);
}
public static void changeNumber(int number) {
System.out.println("2. changeNumber 변경 전, number: " + number);
number = number * 2;
System.out.println("3. changeNumber 변경 후, number: " + number);
}
}
main( ) 에 정의한 변수와 메서드의 매개변수(파라미터) 변수의 이름이 둘 다 number로 같음
실행 결과
//실행 결과
1. changeNumber 호출 전, number: 5
2. changeNumber 변경 전, number: 5
3. changeNumber 변경 후, number: 10
4. changeNumber 호출 후, number: 5
main( )도 사실 메서드임 / 각각의 메서드 안에서 사용하는 변수는 서로 완전히 분리된 다른 변수임
물론 이름이 같아도 완전히 다른 변수 / 따라서 main( )의 number 와 changeNumber( )의 number는 서로 다른 변수임
실행 과정
changeNumber(number); //changeNumber를 호출한다. main의 number(5)
changeNumber(5); //number의 값을 읽는다.
//main의 number값 5가 changeNumber의 number에 복사됨
//결과: main의 number(5), changeNumber의 number(5)
void changeNumber(int number = 5)
//changeNumber의 number에 값 10을 대입
//결과: main 의 number(5), changeNumber의 number(10)
number = number * 2;
main의 number을 출력한다: main의 number의 값인 5가 출력됨
메서드 호출과 값 반환받기
메서드를 사용해서 값을 반환받으려면 메서드의 호출 결과를 반환 받아서 사용하면 됨
예제 MethodValue3 )
package method;
public class MethodValue2 {
public static void main(String[] args) {
int num1 = 5;
System.out.println("changeNumber 호출 전, num1: " + num1);
num1 = changeNumber(num1);
System.out.println("changeNumber 호출 후, num1: " + num1);
}
public static int changeNumber(int num2) {
num2 = num2 * 2;
return num2;
}
}
실행 결과
//실행 결과
changeNumber 호출 전, num1: 5
changeNumber 호출 후, num1: 10
실행 과정
//실행 과정
num1 = changeNumber(num1); //num1(5)
num1 = changeNumber(5);
//호출 시작: changeNumber()
//num1의 값 5가 num2에 대입된다. num1의 값을 num2에 복사한다. num1(5), num2(5)
int changeNumber(int num2=5)
num2 = num2 * 2 //계산 결과: num1(5), num2(10)
return num2; //num2의 값은 10이다.
return 10;
//호출 끝: changeNumber()
num1 = changeNumber(5); //반환 결과가 10이다
num1 = 10; //결과: num1(10)
정리
꼭 기억하기 => 자바는 항상 변수의 값을 복사해서 대입
메서드와 형변환
메서드를 호출할 때도 형변환 적용 / 명시적 형변환, 자동 형변환
명시적 형변환
메소드를 호출하는데 인자와 매개변수의 타입이 맞지 않다면?
예제)
package method;
public class MethodCasting1 {
public static void main(String[] args) {
double number = 1.5;
//printNumber(number); //double을 int에 대입하므로 컴파일 오류
printNumber((int) number); //명시적 형변환을 사용해 double을 int로 변환
}
public static void printNumber(int n) {
System.out.println("숫자: " + n);
}
}
주석 처리 부분 주석을 풀게 되면,,
printNumber(number); //double을 int에 대입하므로 컴파일 오류
다음과 같은 이유로 컴파일 오류 발생
printNumber(number); //number는 1.5 실수
printNumber(1.5) //메서드를 호출하기 전에 number 변수의 값을 읽음
void printNumber(int n = 1.5); //int형 매개변수 n에 double형 실수인 1.5를 대입 시도, 컴파일 오류
이 경우 메서드 호출이 꼭 필요하다면 다음과 같이 명시적 형변환을 사용
printNumber((int) number); //명시적 형변환을 사용해 double을 int로 변환
printNumber(1); //(double)1.5 => (int)1로 변환
void printNumber(int n=1) // int형 파라미터 변수 n에 int형 1을 대입
실행 결과
//실행결과
숫자: 1
자동 형변환
int < long < double
메서드를 호출할 때 매개변수 값을 전달하는 것도 결국 변수에 값을 대입하는 것
따라서 앞서 배운 자동 형변환이 그대로 적용됨
예제)
package method;
public class MethodCasting2 {
public static void main(String[] args) {
int number = 100;
printNumber(number);
}
public static void printNumber(double n) {
System.out.println("숫자: " + n);
}
}
- double형 매개변수(파라미터)에 int형 인수를 전달하는데 문제없이 잘 동작함
//실행 결과
숫자: 100.0
다음과 같이 자동 형변환이 동작함
printNumber(number); //number는 int형 100
printNumber(100); //메서드를 호출하기 전에 number 변수의 값을 읽음
void printNumber(double n = 100) //double형 파라미터 변수 n에 int형 값 100을 대입
void printNumber(double n = (double)100) //double이 더 큰 숫자 범위이므로 자동 형변환 적용
void printNumber(double n = 100.0) //자동 형변환 완료
정리
메서드를 호출할 때는 전달하는 인수의 타입과 매개변수의 타입이 맞아야 함
단, 타입이 달라도 자동 형변환이 가능한 경우, 호출할 수 있음
메서드와 오버로딩
다음과 같은 메서드를 만들고 싶음
- 두 수를 더하는 메서드
- 세 수를 더하는 메서드
이 경우 둘다 더하는 메서드이기 때문에 가급적 같은 이름인 add를 사용하고 싶음
자바는 메서드의 이름 뿐만 아니라 매개변수 정보를 함께 사용해서 메서드를 구분
따라서 다음과 같이 이름이 같고, 매개변수가 다른 메서드를 정의할 수 있음
오버로딩 성공
add(int a, int b)
add(int a, int b, int c)
add(double a, double b)
이름이 같고 매개변수가 다른 메서드를 여러개 정의하는 것을 메서드 오버로딩(Overloading)이라고 함
오버로딩은 번역하면 과적인데, 과하게 물건을 담았다는 뜻 / 따라서 같은 이름의 메서드를 여러개 정의했다고 이해하면 됨
오버로딩 규칙
메서드의 이름이 같아도 매개변수의 타입 및 순서가 다르면 오버로딩을 할 수 있음 / 참고로 변환 타입은 인정하지 않음
다음 케이스는 메서드 이름과 매개변수의 타입이 같으므로 컴파일 오류가 발생 / 반환 타입은 인정하지 않음
오버로딩 실패
int add(int a, int b)
double add(int a, int b)
반환 타입만 다른 경우 오버로딩 불가능
용어 : 메서드 시그니처(method signature)
메서드 시그니처 = 메서드 이름 + 매개변수 타입(순서)
메서드 시그니처는 자바에서 메서드를 구분할 수 있는 고유한 식별자나 서명을 뜻함
메서드 시그니처는 메서드의 이름과 매개변수 타입(순서 포함)으로 구성되어 있음
쉽게 말해 메서드를 구분할 수 있는 기준
자바 입장에서는 각각의 메서드를 고유하게 구분할 수 있어야 함 / 그래야 어떤 메서드를 호출 할 지 결정할 수 있음
따라서 메서드 오버로딩에서 설명한 것 처럼, 메서드 이름이 같아도 메서드 시그니처가 다르면 다른 메서드로 간주
오버로딩이 실패한 예제의 두 메서드를 보면, 두 메서드 add(int a, int b)로 메서드 시그니처가 같음 따라서 메서드의 구분이 불가능하므로 컴파일 오류가 발생하게 됨
int add(int a, int b)
double add(int a, int b)
*반환 타입은 시그니터에 포함되지 않음
int add(int a, int b)
int add(int c, int d)
* 변수의 이름은 상관 x 타입만 보고 구분 (오버로딩 불가)
예제 - 매개변수의 갯수가 다른 오버로딩 )
package method;
public class Overloading1 {
public static void main(String[] args) {
System.out.println("1: " + add(1,2));
System.out.println("2: " + add(1,2,3));
}
public static int add(int a, int b) {
System.out.println("1번 호출");
return a + b;
}
public static int add(int a, int b, int c) {
System.out.println("2번 호출");
return a + b + c;
}
}
1: 정수 1,2를 호출했으므로 add(int a, int b)가 호출됨
2: 정수 1, 2, 3을 호출했으므로 add(int a, int b, int c)가 호출됨
실행 결과
1번 호출
1: 3
2번 호출
2: 6
예제 - 매개변수의 타입이 다른 오버로딩 )
package method;
public class Overloading2 {
public static void main(String[] args) {
myMethod(1, 1.2);
myMethod(1.2, 2);
}
public static void myMethod(int a, double b) {
System.out.println("int a, double b");
}
public static void myMethod(double a, double b) {
System.out.println("double a, int b");
}
}
1: 정수 1, 실수 1.2를 호출했으므로 myMethod(int a, double b)가 호출됨
2: 실수 1.2, 정수 2를 호출했으므로 myMethod(double a, int b)가 호출됨
실행 결과
double a, int b
double a, int b
예제 - 매개변수의 타입이 다른 오버로딩2 )
package method;
public class Overloading3 {
public static void main(String[] args) {
System.out.println("1: " + add(1,2));
System.out.println("2: " + add(1.2,1.5));
}
public static int add(int a, int b) {
System.out.println("1번 호출");
return a + b;
}
public static double add(double a, double b) {
System.out.println("2번 호출");
return a + b;
}
}
1: 정수 1, 정수2를 호출했으므로 add(int a, int b)가 호출됨
2: 실수 1.2, 실수 1.5를 호출했으므로 add(double a, double b)가 호출됨
실행 결과
1번 호출
1: 3
2번 호출
2: 2.7
첫 번째 메서드가 삭제되면? )
package method;
public class Overloading3 {
public static void main(String[] args) {
System.out.println("1: " + add(1,2));
System.out.println("2: " + add(1.2,1.5));
}
public static double add(double a, double b) {
System.out.println("2번 호출");
return a + b;
}
}
1: int형 정수1과 int형 정수2를 호출=> 자동 형변환이 발생해서 add(double a, double b)가 호출됨
2: 실수 1.2와 실수 1.5를 호출 => add(double a, double b)가 호출됨
실행 결과
2번 호출
1: 3.0
2번 호출
2: 2.7
정리=> 먼저 본인 타입에 최대한 맞는 메서드를 찾아 실행, 그래도 없으면 형 변환 가능한 타입의 메서드를 찾아 실행함
'개발 공부 > [java]' 카테고리의 다른 글
[java] 김영한의 실전 자바 기본편 / 강의 정리 / 1. 클래스와 데이터 2 (1) | 2024.02.16 |
---|---|
[java] 김영한의 실전 자바 기본편 / 강의 정리 / 1. 클래스와 데이터 1 (2) | 2024.02.14 |
[java] 김영한의 자바 입문 / 강의 정리 / 9. 메서드 1 (1) | 2024.02.07 |
[java] 김영한의 자바 입문 / 강의 정리 / 8. 배열 2 (1) | 2024.02.06 |
[java] 김영한의 자바 입문 / 강의 정리 / 8. 배열 1 (2) | 2024.02.04 |