Java - 기본기

18-2 메소드 : 메소드 반환 타입, 오버로딩, 매개변수, 호출방식

TerianP 2022. 2. 24.
728x90

메서드인지 메소드 인지 매번 헷갈려요ㅠ

1. 메소드 기본

  • 자주 사용하는 코드를 뽑아서 묶어놓은 것
  • 메서드 선언 방법

void 메서드이름(){

코드;

}

  • 예를 들어 별찍기 코드를 자주 사용한다면 이 코드를 묶어서 하나의 메서드로 만들고 이후 메인 메서드에서 빠르게 실행 할 수 있다.
  • 메서드에서 다른 메서드를 불러 올 수도 있다.
public static void main(String[] args) {
		int count = 0;
		
		PrintStar();
		
		PrintStar();
		
		PrintStar();
				
		for(int i=0; i<3; i++) {
			count++;
			PrintStar();
			System.out.println("count : "+count);
		}
				
		
	}
	
// 별찍기 메서드 생성
	static void PrintStar() {
		for(int i=1; i<=5; i++) {
			for(int j=1; j<=i; j++) {
				System.out.print("*");
			}
			System.out.println();
		}
	}

2. 메서드 매개변수 - void

  • 메서드에서 ( ) 안에 있는 값을 매개변수, 인자, 아큐먼트 라고 한다.
  • 메서드의 매개변수에서 넘어오는 값은 이후 메서드 안에서 유동적으로 할당되어 사용이 가능하다.
  • 아래 구구단 코드에서 num 값을 매개 변수로 받았고, 이를 사용해서 num 단을 출력한다.
  • 이때 매개 변수로 주는 타입과 메서드에서 선언된 타입은 일치해야 한다.

void 매서드명(자료형 매개변수){

코드;

};

  • void 는 매서드 실행 후 호출한쪽으로 아무값도 리턴하지 않는다.
## 메인 메서드 ##
System.out.println("-------------------------");
		printGuGuDan(2);
		printGuGuDan(6);
		printGuGuDan(8);

####

static void printGuGuDan(int num) {
		for(int j=1; j<=9; j++) {
			System.out.println(num+" 단 : "+num+" * "+j+" = "+num*j);
		}
	}

3. 메서드 - 반환타입 & return

  • void 대신 반환하고자하는 자료형 - int , String - , 배열 등등을 메서드명 앞에 쓸 수 있다.
  • 자료형 뿐만 아니라 객체도 쓸 수 있다.
  • 반환 타입이 있는 메서드에서는 반드시!! return 이 포함되어야하며, return 뒤에는 메서드 실행 후 호출한 곳으로 return 뒤에 있는 값을 보내준다.
  • 메서드는 호출한 쪽에는 return 값을 제외한 다른 값에는 영향을 주지 않는다.
public static void main(String[] args) {
	
		// 반환된 결과를 result2 에 저장
		int result2 = minus(100,200);
		System.out.println(result2);
	}
	
	// int 타입의 결과를 반환하는 메서드
	static int minus(int a, int b) {
		int c = a - b;
		
// 결과를 c 에 담아서 반환
		return c;
	}

######### 큰 값 구하기 ############
System.out.println("---------------");
		int max = max(350,200);
		System.out.println(max);

static int max(int a, int b) {
		int max = 0;
		if(a>b) {
			max = a;
		}else {
			max = b;
		}
		return max;
	}

4. 메서드 오버로딩 : 매서드의 이름과 매개변수

  • 메서드 오버로딩은 메서드 명은 동일하나 매개변수의 갯수, 순서, 타입을 다르게 만들면 오버로딩이 된다.
    • 중요한 것은 매개 변수의 갯수, 순서, 타입 3가지 중 하나만 달라도 메서드는 그것을 서로 다른 메서드라고 인식하고, 오버로딩 되었다고 할 수 있다.
  • 매서드는 서로 이름이 동일하더라도 매개변수와 반환 타입이 달라지면 서로 다른 메서드로 인식한다.
  • 즉 똑같은 max 메서드라도 매개변수가 max(int, int) 인 메서드와 max(int, float) 인 메서드는 서로 다르다.
#### 서로 이름은 같지만 기능은 다른 메서드 => 오버로딩된 메서드
static int sum(int a, int b, int c) {
		return a+b+c;
	}
	
	static int sum(int a, int b, int c, int d) {
		return a+b+c+d;
	}
	
	static int sum(int a, float b, int c) {
		return a + (int)b + c;
	}

################ ####################
System.out.println("---------------");
		int result4 = max(110, 210.0f);
		System.out.println(result4);

#####

static int max(int a, float b) {
		if(a > b) {
			return a;
		}else {
			return (int)b;
		}
	}

5. 메서드 매개변수 - 고정인자

  • 메서드의 매개변수는 기본적으로 매서드 선언부에 괄호 안에 선언된 매개변수의 갯수 - ( ) - 만큼만 올 수 있다.
  • 아래처럼 똑같은 avg 메소드를 매개 변수의 갯수만 다르게해서 오버로딩하여 사용 가능하다.
	static int avg(int a, int b) {
		int avg = (a+b)/2;
		return avg;
	}
	
	static int avg(int a, int b, int c) {
		int avg = (a+b+c)/3;
		return avg;
	}
	
	static int avg(int a, int b, int c, int d) {
		int avg = (a+b+c+d)/4;
		return avg;
	}

6. 메소드 매개변수 - 가변인자

  • 매서드의 매개변수는 고정된 값만을 받는것이 아니다.
    • 즉 만약 매개변수 100개 , 1000를 받아야 하는 상황 일 때 선언부에 매개 변수의 갯수를 일일히 적어주지 않아도 된다는 것이다.
  • 매개변수를 내가 원하는 만큼 받을 때, 혹은 받아야 하는 매개 변수의 갯수를 모르는 경우 사용하는 방법이 가변 인자 이다 ⇒ 가변 파라미터
    • 가변인자는 메서드명(자료형 ... 변수명) 으로 사용한다 => 이때 ... 은 정말 사용하는 ... 이다.
  • 이렇게 가변인자를 받게 될 때는 메서드의 인자를 해당 자료형의 배열로 취급한다.
    • 배열로 취급하기 때문에 .length 사용이 가능하다.
    • void Method(int ... num){ => 이라고 할 때 매개변수 num 은 메서드 안에서 사용될 때는 일종의 배열로 취급되어 사용된다.
// 만약 매개변수를 처음부터 지정하는 것이 아니라 내가 원할때마다 바뀌는 값만큼을 받고 싶다면 어떻게할까?
	// 이때 가변 인자를 사용한다.
	// 매개변수에서 ... 을 사용하면 가변 인자를 사용하게 된다.
	// 이때 사용되는 가변인자는 일종의 배열로 취급된다.
	static int avg(int ... data) { // 가변인자 data
		int sum = 0;

		System.out.println("data : "+data);
		
		for(int r : data) {
			System.out.print(r+" ");
		}
		System.out.println();
		
        // 배열로 취급되기 때문에 인자 data 를 사용해 인자의 총 갯수를 알아볼 때
        // data.length 를 사용할 수 있다 => data 배열의 길이 = 총 매개 변수의 갯수
		for(int i=0; i<data.length; i++) {
			sum+=data[i];
		}
		return sum/data.length;
	}

7. 메서드 호출 방식

  • call by value : 메소드로 인자값을 넘길 때, 그 값을 복사하여 넘기기 때문에 메소드 내에서는 복사된 값으로 작업을 하고, 원래의 값을 변경시키지 않는다.
    • 기존 변수의 주소값을 다른 곳에 복사해두고, 복사한 곳에서 작업을 하기 때문에 기존 변수의 주소값에 영향을 미치지 않는다 => 기존변수와 메서드 인자가 바라보는 주소값이 달라짐!!
  • call by reference : 메서드의 매개변수로 주소값을 넣어서 전달하는 경우, 즉 객체나 배열 등의 값을 전달하는 경우 메서드 내에서 변화가 있을 때 이 변화한 내용이 객체나 배열에도 그대로 반영됨 => 기존 변수와 메소드 인자가 바라보는 - 참조하는 - 주소값이 동일!! 서로의 작업에 영향을 미친다.
    • 메소드로 인자값을 넘길 때, 그 객체를 참조하는 주소를 넘기기 때문에 메소드 내에서 원래의 값에 접근이 가능하며 변경시킬 수 있다.
    • 배열처럼 참조 타입들은 - ex) 객체 - 메서드에 인자로 넘겼을 때 call by value 처럼 주소를 복사해서 다른곳에 옮겨두고 사용하는 것이 아니라 같은 주소를 참조하면서 사용하기 때문에 메서드 내에서의 변경, 수정이 메서드 밖의 num 배열에도 영향을 미친다.

public class Quiz02_3 {
	public static void main(String args[]) {
		// method 호출방법에 따라서 크게 2가지로 분류된다.
		// 첫째는 call by value 로 아래와 같이 매개변수로 주소값이 아닌 주소를 복사한 값을
		// 전달하는 방식으로 이는 주소를 복사한 값이기 때문에 기존 변수에 영향을 주지 않는다.
		int a = 2;
		int b = 6;
		printGuGuDan(a, b); // 구구단을 사용하는것은 call by value
		
		// 두번째는 call by reference 로 메서드에 인자값을 넘길때 해당 변수의 주소값을 넘기기 때문에
		// 메서드에서 해당 주소값을 접근할 수 있게 되고, 메서드 내에서 변경가능하며
		// 기존 변수에도 영향을 미친다.
		
		// 아래에서 num 배열과 메서드안에서 사용하는 a 배열의 주소값은 동일!
		// 배열처럼 참조 타입들은 - ex) 객체 - 메서드에 인자로 넘겼을 때
		// call by value 처럼 주소를 복사해서 다른곳에 옮겨두고 사용하는 것이 아니라
		// 그냥 같은 주소를 쓰면서 사용하기 때문에 메서드 내에서의 변경, 수정이
		// 메서드 밖의 num 배열에도 영향을 미친다.
		int[] num = {1,2,3,4,5};
		System.out.println("메서드에서 매개변수 a 배열의 주소값 : "+num);
		Arraysum(num);
	}
	
	static void printGuGuDan(int a, int b) {		
		
		for(int i=a; i<=b; i++) { // 인자로 넘겨받는 a 부터 b 까지 구구단 출력
			for(int j=1; j<=9; j++) { 
				System.out.println(i+" 단 : "+i+" * "+ j +" = "+i*j);
			}
			System.out.println("-----------");
		}
	}
	
	static void Arraysum(int[] a) {
		System.out.println("메서드에서 매개변수 a 배열의 주소값 : "+a);
		int sum = 0;
		
		for(int i=0; i<a.length; i++) {
			sum += a[i];
		}
		System.out.println("sum = "+sum);
	}
	
}

8. 메서드의 매개변수와 참조값

- 앞에서 설명하였듯 call by Reference 의 경우 매개변수로 넘어오는 변수의 주소값으 그대로 복사해서 사용하는 것이 아닌 해당 변수의 주소값을 그대로 참조하여 사용한다.

- 이 때문에 메서드안에서의 변경, 수정이 해당 변수에독 그대로 반영되는 결과 갖는다.

- 이렇게 참조값을 그대로 사용하는 변수의 타입을 Reference type - 참조형 타입 -이라고 하며 아래의 4가지 타입이 이에 해당한다

타입 예시 기본값 할당되는 메모리 크기
배열 Array int[] arr = new int[5] Null 4byte
열거   Null 4byte
클래스 class Music m = new Music(); Null 4byte
인터페이스 interface   Null 4byte

 

9. 공부 정리 - StarCraft 마린으로 알아보기

- 오늘의 공부를 정리해보기 위해 스타크래프트 마린을 한마리 불러오도록 하겠다.

- 먼저 마린의 hp, 위치 좌표, 사거리, 공격력, 방어력, 이동 속도, 공격 속도 등을 정의할 수 있는 필드 변수를 선언한다.

- 이후 생성자를 이용해서 기본 마린의 능력치를 정의한다.

package day7;

public class Marine {
	// member 변수, 필드
	int hp, x, y, range, at_point, de_point;
	int at_speed, mo_speed;
	
	Marine(){
		// 기본 생성자
		// 1. 클래스명과 동일한 이름을 갖는 메서드
		// 2. 객체의 초기화를 담당
		// 3. 리턴값이 없지만 void 키워드 사용 X, void 가 있다면 생성자가 아닌 일반 메서드
		// 4. 생성자는 여러개를 갖을 수 있음
		hp = 50;
		range = 3;
		at_speed = 2;
		mo_speed = 3;
		at_point = 5;
		de_point = 1;
		x = 0;
		y = 0;
		
		System.out.println("기본 생성자 실행");
	}
	
	Marine(int hp, int x, int y, int at_point, int mo_spd){
    // 참조변수 this. 를 사용해서 매개변수의 값을 인스턴스 변수에 넣는다
		this(300, 200, 100);
		this.at_point = at_point;
		this.mo_speed = mo_spd;
		
	}

	void attack(Marine m) {
		// 매개변수 m 에 들어오는 값은 starCraft 의 객체만 올 수 있음
		// 매개변수 m 은 메서드 실행 시 들어오는 인자의 참조 - 주소 -값을 그대로 사용함
		System.out.println("공격하기 메소드의 m : "+m);
		System.out.println(m+ " 에게 공격 중!!");
		
		// 때문에 아래처럼 m.hp 를 찍었을 때 들어오는 인자의 주소값을 보고 hp 를 찾아 갈 수 있고
		// hp 를 깎는 공격 기능을 실행 할 수 있다
		m.hp -= at_point;
	}
	
	void move() {
		x += (int)(Math.random()*10)+1;
		y += (int)(Math.random()*10)+1;
		System.out.println("move, move, move");
	}
	
	void stop() {
		System.out.println("stop!!");
	}
	
	boolean UseStimPack() {
		// 스팀팩 사용하면 체력이 약간 감소
		if(hp > 10) {
			hp -=10;
			at_speed +=3;
			mo_speed +=3;
			System.out.println("오우~~예~~");
			
			return true;
		}else {
			System.out.println("체력이 부족합니다");
			return false;
		}

	}
	
	void patrol() {
		System.out.println("정찰 중");
	}
	
	void status() {
		System.out.println("나는 마린");
		System.out.println("체력 : "+hp);
		System.out.println("x : "+x+" y : "+y);
		System.out.println("attack point : "+at_point);
		System.out.println("depend point : "+de_point);		
		System.out.println("attackSpeed : "+at_speed);
		System.out.println("moveSpeed : "+mo_speed);
	}
	
}

 

- 이렇게 생성된 마린 객체를 2개 생성 후 status 를 통해 현재 상태를 확인한다.

// 공격을 실행할 마린 m1
Marine m1 = new Marine();
m1.status();
		
System.out.println("------------------------------");
// 공격을 당할 마린 m2
Marine m2 = new Marine();
m2.status();


--- 결과 ----
기본 생성자 실행
나는 마린
체력 : 50
x : 0 y : 0
attack point : 5
depend point : 1
attackSpeed : 2
moveSpeed : 3
------------------------------
기본 생성자 실행
나는 마린
체력 : 50
x : 0 y : 0
attack point : 5
depend point : 1
attackSpeed : 2
moveSpeed : 3

 

- attack() 메서드를 통해 마린을 공격해보자

- 이제 실행시켜보면 공격하기 메소드 m 의 주소값과 ~~에게 공격중에서 나오는 주소값이 모두 동일한 것을 알 수 있다.

- 이후 m2 의 status 를 다시 확인해보면 m1 의 공격력만큼 hp가 감소한 것도 확인 할 수 있다. 즉 객체가 매개변수로 넘오는 경우 해당 객체의 주소값을 그대로 참조하며, 메서드를 통한 변동 - hp 감소 - 가 m2 객체의 인스턴스 변수에 반영된 것을 확인 할 수 있다.

##### Marine 메서드 ######

void attack(Marine m) {
		// 매개변수 m 에 들어오는 값은 starCraft 의 객체만 올 수 있음
		// 매개변수 m 은 메서드 실행 시 들어오는 인자의 참조 - 주소 -값을 그대로 사용함
		System.out.println("공격하기 메소드의 m : "+m);
		System.out.println(m+ " 에게 공격 중!!");
		
		// 때문에 아래처럼 m.hp 를 찍었을 때 들어오는 인자의 주소값을 보고 hp 를 찾아 갈 수 있고
		// hp 를 깎는 공격 기능을 실행 할 수 있다
		m.hp -= at_point;
}

############ Main 메서드 #########
System.out.println("------------------------------");
m1.attack(m2);
m2.status();


#### 결과 ####

System.out.println("------------------------------");
공격하기 메소드의 m : day7.Marine@436e852b
day7.Marine@436e852b 에게 공격 중!!
나는 마린
체력 : 45
x : 0 y : 0
attack point : 5
depend point : 1
attackSpeed : 2
moveSpeed : 3

참고 자료

- 자바 메서드 호출 방식 2종류

https://velog.io/@ahnick/Java-Call-by-Value-Call-by-Reference

 

[Java] Call by Value, Call by Reference

프로그래밍 언어들의 메소드 매개변수 호출 방식에는 여러 가지가 있으며 호출 방식은언어마다 다르게 되어 있습니다. 그 중 자바의 Call by Value 방식에 대해 알아봅시다 !

velog.io

 

댓글