[Java] 자바의 정석 6장 (2) - 메서드

토닉·2021년 8월 31일
0

Java

목록 보기
8/13
post-thumbnail

메서드

정의

  • 문장들을 묶어 놓은 것

목적

  • 중복되는 코드를 없애기 위해

장점

  • 코드의 중복, 유지보수, 재사용, 가독성

메서드는 위처럼 여러번 반복되는 코드를 없애기 위해서 사용됩니다.

class Test {
  public static void main(String[] args){
    int a = 10;
    int b = 20;
    int a_b = a+b; // 중복
    
    int c = 5;
    int d = 15;
    int c_d = c+d; // 중복
  }

}

위와 같이 똑같은 연산을 하는 코드가 중복이 될 때 메서드에 작성할 수 있습니다.

class Test {
  public static void main(String[] args){
    int a = 10;
    int b = 20;
    int a_b = add(a,b);
    
    int c = 5;
    int d = 15;
    int c_d = add(c,d);
  }
  
  int add(int num1, int num2){
    return num1+num2;
  }
}

간단한 코드를 예시로 들었지만 만약 조금만 더 복잡해지면 메서드를 활용하는 것이 훨씬 보기 편하다는 것을 알 수 있습니다.
예를 들어 두 수 중 큰 값을 고르는 코드를 작성할 때

class Test {
  public static void main(String[] args){
    int a = 10;
    int b = 20;
    int a_b = max(a,b);
    
    int c = 5;
    int d = 15;
    int c_d = max(c,d);
  }
  
  int max(int num1, int num2){
    return num1 > num2 ? num1 : num2;
  }
}

메서드 = 선언부 + 구현부

메서드는 아래와 같이 작성됩니다.

반환값타입  이름(매개변수1, 매개변수2 ...){
     // 구현코드
     return 반환값

}
int max(int num1, int num2){ // 선언부
    return num1 > num2 ? num1 : num2; // 구현부
}

선언부

반환값 타입

기본형타입, 참조형타입, void(반환값이 없을 때) 3가지를 작성할 수 있습니다.

이름

소문자로 작성합니다.
줄임말보다는 읽었을 때 어떤 동작을 하는지 알기 쉽게 작성해야 합니다.

매개변수

메서드를 호출할 때 들어가는 값
없어도 됩니다.
매개변수도 메서드의 지역변수 입니다.

기본형, 참조형 매개변수

매개변수에는 기본형과 참조형도 들어갈 수 있습니다.(참조형이란 객체의 주소, 참조변수)
두 차이점
기본형 매개변수: 변수의 값을 읽기만 할 수 있다.(read only)
참조형 매개변수: 변수의 값을 읽고 변경할 수 있다.(read & write)

class Data { int x; }

class Test {
	public static void main(String[] args) {
		Data d = new Data();
		d.x = 10;
		System.out.println("main() : x = " + d.x);

		change(d.x);
		System.out.println("After change(d.x) 기본형");
		System.out.println("main() : x = " + d.x);

		change(d);
		System.out.println("After change(d) 참조형");
		System.out.println("main() : x = " + d.x);

		Data d2 = copy(d);
		System.out.println("copy(d) : d2.x = " + d2.x);
		System.out.println("d = " + d);
		System.out.println("d2 = " + d2);
	}

	static void change(int x) { // 기본 자료형 -> 읽기만
		x = 1000;
		System.out.println("change(기본형) : x = " + x);
	}

	static void change(Data d){ // 참조 자료형 -> 읽기, 쓰기 가능
		d.x = 1000;
		System.out.println("change(참조형) : x = " + d.x);
	}

	static Data copy(Data d){ // 객체 복사
		Data temp = new Data();
		temp.x = d.x;
		return temp;
	}
}

위 코드에는 두 개의 change 메서드가 있습니다.(오버로딩으로 같은 이름의 메서드 작성 가능)
기본 자료형의 값이 들어갈 때 이 기본 자료형은 change 메서드의 지역 변수입니다.
따라서 메서드의 호출이 끝나면 지역 변수도 같이 없어지기 때문에 실제 들어간 값이 바뀌어서 저장되지 않습니다.

참조 자료형이 들어갈 때는 객체의 주소의 값이 들어간다고 보면 됩니다.
객체의 주소로 들어가 인스턴스 변수를 수정한다면 change 메서드가 호출이 끝나도 인스턴스는 없어지지 않기 때문에 수정한 값이 저장됩니다.

오버로딩이란?
한 클래스 안에 같은 이름의 메서드를 여러 개 정의하는 것
규칙
1. 메서드 이름이 같아야 한다.
2. 매개변수의 개수 또는 타입이 달라야 한다.
3. 반환 타입은 영향없다.

잘못된 경우

// 잘못 오버로딩된 경우
int add(int a, int b){ return a+b; }

int add(int x, int y){ return x+y; }

// 반환값만 다른 경우
long add(int a, int b){ return a+b; }

int add(int x, int y){ return x+y; }

ambiguous error

// 작성은 된다.
long add(long a, int b){ return a+b; }

long add(int x, long y){ return x+y; }

// 단 위 메서드를 다음과 같이 호출하면 에러!
add(3,3);
// 두 메서드 다 가능하기 때문에 어떤 메서드를 작성할지 애메해진다.(ambiguous error!)

올바른 예시

// 올바른 예시
class Ex6_6 {
	public static void main(String[] args) {
		MyMyMath.add(10,20);
		MyMyMath.add(10L,20);
		MyMyMath.add(10,20L);
		MyMyMath.add(10L, 20L);

	}
}

class MyMyMath {

	static int add(int a, int b){
		System.out.println("int add(int a, int b) - " + (a+b));
		return a + b;
	}

	static long add(int a, long b){ // 두 번째 매개변수 타입이 다르다.
		System.out.println("long add(int a, long b) - " + (a+b) );
		return a + b;
	}

	static long add(long a, int b){ // 첫 번째 매개변수 타입이 다르다.
		System.out.println("long add(long a, int b) - " + (a+b) );
		return a + b;
	}

	static long add(long a, long b){ // 두 매개변수 타입이 모두 다르다.
		System.out.println("long add(long a, long b) - " + (a+b));
		return a + b;
	}

}

>> int add(int a, int b) - 30
>> long add(long a, int b) - 30
>> long add(int a, long b) - 30
>> long add(long a, long b) - 30

구현부

구현코드

메서드를 호출했을 때 실행시킬 코드를 작성합니다.(메서드의 {}안에)

반환값(return)

규칙
1. 반환타입이 void가 아니라면 무조건! 반환타입에 맞는 return 을 작성해야 합니다.
2. void 일 땐 선택적으로 return 만 작성할 수 있습니다.
3. 만약 구현코드에 조건절이 있어 true/false일 때 실행되는 코드가 다르다면 두가지 경우 모두 return 을 작성해주어야 합니다.(void가 아닐 경우 / void일 경우 선택적으로)

메서드를 활용한 계산기 구현

//계산기 클래스 메서드 호출
public class TestMain {
    public static void main(String[] args){
        Calculator calculator = new Calculator();
        calculator.print(calculator.add(10,5));
        calculator.print(calculator.subtrack(10,5));
        calculator.print(calculator.multiply(10,5));
        calculator.print(calculator.divide(10,5));
        calculator.print(calculator.max(10,5));
        calculator.print(calculator.min(10,5));
    }
}

class Calculator {
    int add(int a, int b) { return a + b; }

    int subtrack(int a, int b){ return a - b; }

    int multiply(int a, int b){ return a * b; }

    int divide(int a, int b){ return a / b; }

    int max(int a, int b){ return a > b ? a : b; }

    int min(int a, int b){ return a < b ? a : b; }

    void print(int result){ System.out.println("result = " + result); }
}

result = 15 // add(10,5)
result = 5 // subtrack(10,5)
result = 50 // multiply(10,5)
result = 2 // divide(10,5)
result = 10 // max(10,5)
result = 5 // min(10,5)

메서드와 함수는 무엇이 다른가요?
메서드는 클래스안에 있고 함수는 독립적입니다.
근본적으로는 같은 것이라고 생각하면 됩니다.

static 메서드와 인스턴스 메서드

인스턴스 변수(iv)와 클래스 변수(cv)의 차이점과 비슷합니다.

static 메서드

  • 객체(인스턴스) 생성없이 클래스이름.메서드이름() 으로 호출
  • 인스턴스 멤버와 관련없는 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수(iv) 사용 불가

인스턴스 메서드

  • 인스턴스 생성 후, 참조변수.메서드이름() 으로 호출
  • 인스턴스 멤버와 관련된 작업을 하는 메서드
  • 메서드 내에서 인스턴스 변수 사용가능

static은 인스턴스 변수를 사용하지 않을 때 붙이면 됩니다.
다른 의미로 객체(인스턴스)를 생성하지 않더라도 사용할 수 있는 메서드라면 static을 붙여줍니다.
인스턴스 메서드는 인스턴스 변수(iv)가 필요하기 때문에 객체(인스턴스)를 생성하고 사용할 수 있습니다.

class Ex6_6 {
	public static void main(String[] args) {
		Card c1 = new Card();
		Card c2 = new Card();

		c1.setKind("Heart");
		c1.setNumber(5);
		c2.setKind("spade");
		c2.setNumber(10);

		Card.setHeight(100);
		Card.setWidth(50);

		System.out.printf("c1 - kind: %s | number: %d | height: %d | width: %d%n",
				c1.kind, c1.number, c1.height, c1.width);
		System.out.printf("c2 - kind: %s | number: %d | height: %d | width: %d%n",
				c2.kind, c2.number, c2.height, c2.width);
	}
}

class Card {
	// iv
	String kind;
	int number;

	// cv
	static int width = 100;
	static int height = 250;

	// 클래스 메서드
	static void setWidth(int n){
		width = n;
	}
	static void setHeight(int n){
		height = n;
	}

	// 인스턴스 메서드
	void setKind(String s){
		kind = s;
	}
	void setNumber(int n){
		number = n;
	}


}

위 코드를 예시로 들면

  • 카드의 width, height은 클래스 변수이다.
  • 따라서 모든 카드의 공통적인 변수이기 때문에 클래스 변수이고 이를 수정할 때는 클래스 메서드 즉 static 메서드로 작성해야 한다.
  • 카드의 숫자와 모양은 개별적인 특성이 있기 때문에 인스턴스 변수이다.
  • 인스턴스 변수의 값을 변경하기 위해서는 인스턴스 변수가 있어야 함으로 객체(인스턴스)를 생성 후 관련 메서드를 사용할 수 있다.

메서드 끼리는?
마찬가지로 static 메서드는 인스턴스 변수와 인스턴스 메서드를 호출할 수 없다.

profile
우아한테크코스 4기 교육생

0개의 댓글

관련 채용 정보