Loading...

JAVA / / 2022. 1. 12. 16:32

자바 13강. 메서드

반응형

클래스의 행위에 대해 알아보자.

 

행위 = 메서드

행위는 " 메서드 이름 + ( ) + { } " 구조로 만들어진다.

 

void drink ( ) {

 

}               

 

이 구조를 가진 것들은 메서드이다.

 

main도 같은 구조를 가지고 있으니 메서드이다.

 

행위 안에 행위를 추가할 수 없다.

 

메서드 = 블랙박스(캡슐화) 혹은 매직박스라고도 함

호출만 해!

캡슐화 : 호출하면 뭐가 나올지만 알면되고

구조와 원리는 이해할 필요 없음

 

(ex. 엑셀 밟으면 자동차가 앞으로 나감

메서드를 호출하면 차가 앞으로 나가는 행위

 

엑셀 : 메서드를 호출하는 하나의 인터페이스)

 

 

세상의 모든 것들은 호출해서 아웃풋이 나온다.

그리고 대부분 모든 사람들은 호출해서 왜 어떻게 아웃풋이 나오는지 모른다.

캡슐화된 메서드를 호출만 하기 때문이다.

 

개발자는 블랙박스를 만들어 사용자들(일반인)에게 주면

사용자들이 실행만 시킨다.

남이 잘 만들어놓은 블랙박스를 가져와서 자신이 쓸 수도 있다.(라이브러리)

 

우리는 이 블랙박스 만드는 것을 배울 것이고

활용도 할 것이다.

 

메서드에 출구가 없다는 말은 반환 값이 없다는 말과 같다.

이때는 void를 써서 출구가 없다는 것을 알려준다.

 

이후 메서드에서 특정한 역할(목적)을 수행하기 위해

전달받을 인수(argument)가 있다면 타입과 변수명을 써서

인수의 타입을 알려준다.

 

저 그림을 코드로 만들어보면 이렇게 짤 수 있다.

new를 사용하지 않고 결과를 확인하기 위해 static을 붙여주었다.

package ex07;

public class MethodEx01 {

    static void add(int num) { // 투입구에 정수형 받기
        System.out.println("받은 숫자는 " + num);
    }

    public static void main(String[] args) {
    
        // 같은 클래스 내부이기 때문에 클래스 이름 생략 가능
        // add(5000); 가능
        MethodEx01.add(5000); // 메서드 호출
    }
}

 

입구가 2개 있고 출구도 있는 minus 메서드를 만들어보자.

 

출구가 있기 때문에 void를 쓰지 않고 출구에서 뱉어낼 값의 타입에 맞게 적어준다.

우리는 숫자를 뱉어낼 것이기 때문에 int라고 적어줬다.

괄호 안에 인수를 받을 건데 출구가 2개일 때는 콤마(,)로 구분해서 적어주면 된다.

2개뿐만 아니라 필요한 만큼 만들 수 있다.

 

출구에서 값을 뱉어낼 때는 return을 사용한다.

package ex07;

public class MethodEx01 {

    static int minus(int a, int b) { // 투입구에 정수형 받기

        return a - b;
    }

    public static void main(String[] args) {
        MethodEx01.minus(20, 10); // 메서드 호출
    }
}

이렇게 return 받은 값을 새 변수에 초기화해줄 수 있다.

package ex07;

public class MethodEx01 {

    static int minus(int a, int b) { // 투입구에 정수형 받기

        return a - b;
    }

    public static void main(String[] args) {
        MethodEx01.minus(20, 10); // 메서드 호출
        // return값으로 변수 초기화
        int result = minus(20, 10);
        System.out.println(result);
    }
}

위에서 알아본 것을 토대로 계산기 프로그램을 만들어보자.

 

1. 출구 없이 void 사용한 메서드

package ex00;

// 계산기 클래스
class Calculator {

    // add 뒤에 있는 ()는 입구, 입구는 무조건 있어야함
    // void는 출구가 없다.
    void add(int n1, int n2) { // 입구만 있는 메서드, 돈 먹은 자판기
        System.out.println("더하기 메서드입니다.");
        System.out.println(n1 + n2);
    }

    // minus
    // add와 minus 메서드의 stack 공간이 다르기 때문에
    // add와 minus의 n1, n2는 다른공간
    void minus(int n1, int n2) {
        System.out.println("빼기 메서드입니다.");
        System.out.println(n1 - n2);
    }

    // multi (곱하기)
    void multi(int n1, int n2) {
        System.out.println("곱하기 메서드입니다.");
        System.out.println(n1 * n2);
    }

    // divide (나누기)
    void divide(int n1, int n2) {
        System.out.println("나누기 메서드입니다.");
        System.out.println(n1 / n2);
    }
}

public class MethEx01 {
    public static void main(String[] args) {
        Calculator c1 = new Calculator();
        c1.add(3, 5);
        c1.minus(3, 5);
        c1.multi(3, 5);
        c1.divide(3, 5);
    }
}

코드 꾸러미, 코드의 집합을 모듈이라고 한다.

class Calculator는 4개의 모듈을 가지고 있는 라이브러리라고 볼 수 있다.

라이브러리 = 모듈의 모둠

 

2. 투입구, 출구 모두 다 있는 메서드

package ex00;

class Cal {

    // 투입구, 출구 다 있는 메서드
    static int add(int a1, int a2) {
        return a1 + a2;
    }

    static int multi(int a1, int a2) {
        return a1 * a2;
    }
}

public class MethEx02 {
    public static void main(String[] args) {

        // 메서드 호출
        int r1 = Cal.add(20, 50); // return값을 받을 변수 r1 초기화
        System.out.println(r1);
        int r2 = Cal.multi(r1, 10);
        System.out.println(r2);
    }
}

 


 

2번 코드의 실행 과정을 그림으로 그려보자.

 

1. JVM이 static을 찾아 메모리에 띄움

2. main을 찾아 실행

3. stack에 main영역이 열림

4. main Queue 생성

5. 메인 큐에 문장(Statement) 단위로 한 줄씩 쌓이고

19번 문장(int r1 = Cal.add(20, 50);)부터 시작

오른쪽 항부터 인식 Cal.add( ) 메서드 호출

 

* 19번 문장 끝나지 않음

JVM이 19번 문장 절반 정도 실행했다는 context를 기억하고 있음 *

 

6. add stack 생성

7. add Queue 생성 후 문장 단위로 한 줄씩 쌓임

8. add 큐의 투입구 실행

9. add stack에 a1 = 20, a2 = 50 저장

10. add 메서드의 7번 문장 실행

11. a1 + a2의 값을 19번 문장으로 return 후

main Queue의 19번 문장으로 복귀

12. add Queue 날아감 -> add stack 날아감

13. 19번 문장에서 r1 선언 후 return값으로 초기화

14. r1 = 70을 main stack에 저장

15. 20번 문장 실행 -> 출력

16. 21번 문장(int r2 = Cal.multi(r1, 10);) 실행

오른쪽 항부터 인식 Cal.multi( ) 메서드 호출

 

* 21번 문장 끝나지 않음

JVM이 21번 문장 절반 정도 실행했다는 context를 기억하고 있음 *

 

17. multi stack 생성

18. multi Queue 생성 후 문장 단위로 한 줄씩 쌓임

19. multi 큐의 투입구 실행

20. multi stack에 a1 = 70, a2 = 10 저장

 

* add stack과 multi stack의 공간 자체가 다르기 때문에

a1, a2 이름이 같아도 상관없음 

 

21. multi 메서드의 11번 문장 실행

22. a1 * a2 값을 21번 문장으로 return 후

main Queue의 21번 문장으로 복귀

23. multi Queue 날아감 -> multi stack 날아감

24. 21번 문장에서 r2 선언 후 return값으로 초기화

25. r2 = 700을 main stack에 저장

26. 22번 문장 실행 -> 출력

27. main이 할 일을 다함

main Queue 날아감 -> main stack 날아감

프로그램 종료 

 


 

이 코드에서 start 메서드 내부의 sum에서 오류가 발생했다.

이유는 무엇일까?

위 코드의 메모리 상태를 보면 이렇게 되어있다.

static에 start와 main이 띄워져 있고,

JVM은 main을 찾아 실행시킨다.

main에서 start 메서드를 호출시킬 수 있는 이유는

start 메서드가 이미 static 메모리에 띄워져 있기 때문이다.

 

start메서드를 실행하면 n1 = 10, n2 = 20, result = 30 정보가

start stack에 저장된다.

그동안에 변수 sum이 선언되지도 않았고,

메모리 어디에도 떠있지 않기 때문에 오류가 발생하는 것이다.

 

이때 오류를 해결하기 위해 어떻게 해야 할까?

 

main에서 start메서드를 호출하기 전

MethEx03 m = new MethEx03( );

을 하여 heap 공간에 static이 아닌 모든 것을 띄워준다.

 

하지만 오류가 사라지지 않을 것이다.

메서드를 호출하기 전에 heap에 동적 할당해주면

메모리적으로는 아무런 문제가 없다.

 

new를 이용해 메서드보다 먼저 할당하냐, 메서드보다 뒤에 할당하냐

타이밍의 차이로 프로그램의 결과가 바뀔 수 있는데

코드를 짜는 사람이 앞에 쓸지 뒤에 쓸지 모르니까

그냥 자바에서 금지시켜버렸다.

(다른 언어에서는 다를 수 있음)

 

때문에 이 오류를 해결하기 위해서는 start 메서드의 static을 지우고

MethEx03 클래스를 한 번에 동적 할당해주면

start 메서드와 변수 sum 모두 heap에 할당되어

오류가 사라질 것이다. 

그리고 start 메서드를 호출할 때는 부여했던 이름을 참조하여 호출해준다.

package ex00;

public class MethEx03 {

    int sum = 0;

    void start() { // 출구 없음, 투입구만 있음, 인자는 없음
        int n1 = 10;
        int n2 = 20;
        int result = n1 + n2;
        sum = result;
    }

    public static void main(String[] args) {
        MethEx03 m = new MethEx03(); 	// call by reference
        m.start(); // 같은 클래스에 있기 때문에, 클래스명 생략 가능
                   // start의 내부 실행됨(큐 호출)
        System.out.println(m.sum);// 메서드의 실행결과를 힙에 보관
    }
}

따라서 정리해보면

static 메서드 내부에서는 heap에 있는 데이터(상태 데이터)를 찾을 수가 없다.

 

 

 

 

메서드 규칙

1. 투입구와 출구가 있다. 단, 출구는 항상 필요하지는 않다.
2. 메서드는 하나의 모듈(특정한 역할, 목적을 수행하는)이 될 수 있다.
3. 출구가 없을 때 void 사용, 출구가 있을 때는 return값의 타입과 동일하게 해 준다.
4. 메서드 내부(Queue)를 몰라도 사용할 수 있다.(캡슐화)
5. 메서드는 1급 객체인가? -> 아니다. 자바에서는 1급 객체가 class밖에 없다.
6. 메서드는 왜 만들어? 특정한 역할, 목적을 수행하는 코드 꾸러미를 만들어 두려고
   -> 캡슐화, 재사용, 코드 관리도 편함, 메모리 관리에도 더욱 효과적(호출할 때만 뜰 거니까) 
7. static 메서드 내부에서는 heap에 있는 데이터(상태 데이터)를 찾을 수 없다.

 

 

[출처]

 

https://cafe.naver.com/metacoding

 

메타코딩 : 네이버 카페

코린이들의 궁금증

cafe.naver.com

메타 코딩 유튜브

https://www.youtube.com/c/%EB%A9%94%ED%83%80%EC%BD%94%EB%94%A9

 

메타코딩

문의사항 : getinthere@naver.com 인스타그램 : https://www.instagram.com/meta4pm 깃헙 : https://github.com/codingspecialist 유료강좌 : https://www.easyupclass.com

www.youtube.com

 

반응형