1. 메서드 시작

함수(Function)

함수(function)란 하나의 특별한 목적의 작업을 수행하도록 설계된 독립적인 블록을 의미한다.
이러한 함수는 필요할 때마다 호출하여 해당 작업을 반복해서 수행할 수 있다.

자바에서는 함수메서드(Method)라 한다.

package method;
public class Method1Ref {
    public static void main(String[] args) {
        //계산1
        int sum1 = add(5,10);
        System.out.println("결과1 출력:" + sum1);

        //계산2
        int sum2 = add(15, 20);
        System.out.println("결과2 출력:" + sum2);
    }

    //add 메서드
    public static int add(int a, int b) {
        System.out.println(a + "+" + b + " 연산 수행");
        int sum = a + b;
        return sum;
    }
}

실행 결과

 

메서드 정의

public static int add(int a, int b) {
    System.out.println(a + "+" + b + " 연산 수행");
    int sum = a + b;
    return sum;
}

함수를 정의한다 = 메서드를 정의한다

메서드: 메서드 선언 + 메서드 본문

 

메서드 선언(Method Declaration)

public static int add(int a, int b)

public static

    ○ public: 다른 클래스에서 호출할 수 있는 메서드

    static: 객체를 생성하지 않고 호출할 수 있는 정적 메서드

    지금은 단순하게 메서드를 만들 때 둘을 사용해야 한다고 생각하자.

int add(int a, int b)

      int: 반환 타입 정의. 메서드의 실행 결과를 반환할 때 사용할 반환 타입을 지정한다.

      add: 메서드에 이름을 부여. 이 이름으로 메서드를 호출할 수 있다.

      (int a, int b): 메서드를 호출할 때 전달하는 입력 값을 정의. 이 변수들은 해당 메서드 안에서만 사용된다.

    → 메서드 선언에 사용되는 변수: 파라미터(parameter) = 매개변수

 

 

메서드 본문(Method Body)

{
    System.out.println(a + "+" + b + " 연산 수행");
    int sum = a + b;
    return sum;
}
  • 메서드가 수행해야 하는 코드 블록이다.
  • 메서드를 호출하면 메서드 본문이 순서대로 실행된다.
  • 메서드 본문은 블랙박스이다. 메서드를 호출하는 곳에서는 메서드 선언은 알지만 메서드 본문은 모른다.
  • 메서드의 실행 결과를 반환하려면 return문을 사용해야 한다. return sum: sum 변수에 들어있는 값을 반환

 

메서드 호출

int sum1 = add(5,10);
int sum2 = add(15, 20);

 

메서드 호출 순서

int sum1 = add(5, 10); //add라는 메서드를 숫자 5,10을 전달하면서 호출한다.
int sum1 = 15; //add(5, 10)이 실행된다. 실행 결과는 반환 값은 15이다.
//sum1에 15 값이 저장된다.

 

 

메서드 호출과 용어 정리

메서드를 호출할 때는 다음과 같이 메서드에 넘기는 값과 매개변수(파라미터)의 타입이 맞아야 한다.

넘기는 값과 매개변수(파라미터)의 순서와 갯수도 맞아야 한다.

호출: call("hello", 20)
메서드 정의: int call(String str, int age)

 

인수(Argument)

인수 = 인자 = 아규먼트

함수가 호출될 때 함수로 값을 전달해주는 값

"hello", 20처럼 넘기는 값. 메서드 내부로 들어가는 값

 

매개변수(Parameter)

매개변수 = 파라미터

중간에서 전달하는 변수

String str, int age를 매개변수, 파라미터라 한다.

메서드를 호출할 때 인수를 넘기면, 그 인수가 매개변수에 대입된다.

 

 

2. 메서드 정의

제어자 반환타입 메서드이름 (매개변수 목록) {
    메서드 본문
}

 

ex1)

public static int add (int a, int b){
    // 메서드 본문, 실행코드
}

    

ex2)

public static void printHeader( ){
    // 메서드 본문, 실행코드
}

 

  • 제어자(Modifier): public, static과 같은 부분
  • 반환 타입(Return Type): 메서드가 실행된 후 반환하는 데이터 타입을 지정. 메서드가 값을 반환하지 않는 경우, 없다는 뜻의 void를 사용해야 한다.
  • 메서드 이름(Method Name): 메서드의 이름은 메서드를 호출하는 데 사용된다.
  • 매개변수(Parameter): 메서드 내부에서 사용할 수 있는 변수. 매개변수는 옵션이다. 입력값이 필요 없는 메서드는 매개변수를 지정하지 않아도 된다. ex) printHeader( )
  • 메서드 본문(Method Body): 실제 메서드의 코드가 위치한다. 중괄호 { } 사이에 코드를 작성한다.

 

매개변수가 없고, 반환 타입이 없는 경우

package method;

public class Method2 {
    public static void main(String[] args) {
        printHeader();
        System.out.println("프로그램이 동작합니다.");
        printFooter();
    }
    public static void printHeader(){
        System.out.println("= 프로그램을 시작합니다 =");
        return; //void의 경우 생략 가능
    }

    public static void printFooter() {
        System.out.println("= 프로그램을 종료합니다 =");
    }
}

실행 결과

 

printHeader(), printFooter() 메서드는 매개변수가 없고, 반환타입도 없다.

 

● 매개변수가 없는 경우

    선언: public static void printHeader()와 같이 매개변수를 비워두고 정의하면 된다.

    호출: printHeader(); 와 같이 인수를 비워두고 호출하면 된다.

● 반환 타입이 없는 경우

    선언: public static void printHeader()와 같이 반환타입을 void로 정의하면 된다.

    호출: printHeader(); 와 같이 반환 타입이 없으므로 메서드만 호출하고 반환 값을 받지 않으면 된다.

        ※ String str = printHeader(); 반환 타입이 void이기 때문에 이렇게 반환 값을 받으면 컴파일 오류가 발생함

 

void와 return 생략

모든 메서드는 항상 return을 호출해야 한다. 그런데 반환 타입 void의 경우에는 예외로 printFooter()와 같이 생략해도 된다.

 

 

3. 반환 타입

반환 타입이 있으면 반드시 값을 반환해야 한다.

반환 타입이 있는 메서드는 반드시 return을 사용해서 값을 반환해야 한다.

특히 조건문에서 주의해야 한다.

 

[수정 전]

package method;

public class MethodReturn1 {
    public static void main(String[] args) {
        boolean result = odd(2);
        System.out.println(result);
    }

    public static boolean odd(int i){
        if (i % 2 ==1){
            return true;
        }
    }
}

if 조건이 만족하면 true를 반환하지만, 조건을 만족하지 않으면 return문이 실행되지 않는다.

따라서 이 코드를 실행하면 return문을 누락했다는 컴파일 오류가 발생한다.

실행 결과 (컴파일 오류)

 

[수정 후]

package method;

public class MethodReturn1 {
    public static void main(String[] args) {
        boolean result = odd(2);
        System.out.println(result);
    }

    public static boolean odd(int i){
        if (i % 2 ==1){
            return true;
        } else {
            return false;
        }
    }
}

이렇게 수정하면 if 조건을 만족하지 않아도 else를 통해 return문이 실행된다.

실행 결과

 

 

return문을 만나면 그 즉시 메서드를 빠져나간다.

 

다음 로직을 수행하는 메서드를 만들어보자.

  • 18살 미만의 경우: 미성년자는 출입이 불가합니다.
  • 18살 이상의 경우: 입장하세요.

[수정 전]

package method;

public class MethodReturn2 {
    public static void main(String[] args) {
        checkAge(10);
        checkAge(20);
    }

    public static void checkAge(int age) {
        if (age < 18) {
            System.out.println(age + "살, 미성년자는 출입이 불가능합니다.");
        }
        System.out.println(age + "살, 입장하세요.");
    }
}

실행 결과

18세 미만의 경우 "미성년자는 출입이 불가능합니다."를 출력하고, 그 다음 줄에 return이 없기 때문에 해당 메서드를 빠져나가지 않고 다음 로직을 수행하여 "입장하세요."도 같이 출력된다.

 

[수정 후]

package method;

public class MethodReturn2 {
    public static void main(String[] args) {
        checkAge(10);
        checkAge(20);
    }

    public static void checkAge(int age) {
        if (age < 18) {
            System.out.println(age + "살, 미성년자는 출입이 불가능합니다.");
            return;
        }
        System.out.println(age + "살, 입장하세요.");
    }
}

실행 결과

  • 18세 미만의 경우 "미성년자는 출입이 불가능합니다."를 출력하고 바로 return문이 수행된다. 따라서 다음 로직을 수행하지 않고, 해당 메서드를 빠져나온다.
  • 18세 이상의 경우 "입장하세요"를 출력하고, 메서드가 종료된다. 참고로 반환 타입이 없는 void형이기 때문에 마지막 줄의 return은 생략할 수 있다.

 

※ 반환 값 무시

반환 타입이 있는 메서드를 호출했는데 만약 반환 값이 필요없다면 사용하지 않아도 된다.

package method;
public class Method1Ref {
    public static void main(String[] args) {
        //계산1
        int sum1 = add(5,10);
        System.out.println("결과1 출력:" + sum1);

        //계산2
        int sum2 = add(15, 20);
        System.out.println("결과2 출력:" + sum2);

        add(100, 200);
    }

    //add 메서드
    public static int add(int a, int b) {
        System.out.println(a + "+" + b + " 연산 수행");
        int sum = a + b;
        return sum;
    }
}

실행 결과

  • int sum1 = add(5, 10); , int sum2 = add(15, 20); // 반환된 값을 받아서 sum1, sum2에 각각 저장했다.
  • add(100, 200); // 반환된 값을 사용하지 않고 버린다. 호출 결과를 변수에 담지 않고 단순히 메서드만 호출했다.

 

 

4. 메서드 호출과 값 전달

자바는 항상 변수의 값을 복사해서 대입한다.

 

변수의 값 복사

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);
    }
}

실행 결과

 

실행 과정

int num2 = num1; //num1의 값은 5이다. num1(5)
int num2 = 5; //num2 변수에 대입하기 전에 num1의 값 5를 읽는다. 결과: num1(5), num2(5)
num2 = 10; // num2에 10을 대입한다. 결과: num1(5), num2(10)

 

[값을 복사해서 대입하는 부분]

int num2 = num1;

num1에 있는 값 5를 복사해서 num2에 넣는다.

  • "복사한다": num1의 값을 읽어도 num1에 있는 기존 값이 유지되고, 새로운 값이 num2에 들어가기 때문이다.            마치 num1의 값이 num2에 복사가 된 것 같다.
  • num1이라는 변수 자체가 num2에 들어가는 것이 아니다. num1에 들어있는 값을 읽고 복사해서 num2에 넣는 것이다.
  • num1에 있는 값을 num2에 대입한다고 표현한다. 하지만 실제로는 그 값을 복사해서 대입하는 것이다.

 

메서드 호출과 값 복사

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);
    }
}

실행 결과

changeNumber(num1);

num1의 값 5를 읽고 복사해서 num2에 전달

public static void changeNumber(int num2 = 5)

num2의 변경은 num1에 영향을 주지 않는다. 왜냐하면 앞서 값을 복사해서 전달했기 때문이다.

 

결과적으로 매개변수 num2의 값만 10으로 변경되고 num1의 값은 변경되지 않고 기존 값인 5로 유지된다.

자바는 항상 값을 복사해서 전달하기 때문에 num2의 값을 바꾸더라도 num1에는 영향을 주지 않는다.

 

 

메서드 호출과 이름이 같은 변수

같은 문제를 호출자의 변수 이름과 매개변수의 이름을 같게 해서 한번 더 풀어보자.

이번에는 main()에 정의된 변수와 메서드의 매개변수(파라미터)의 이름이 둘다 number로 같다.

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는 각각의 메서드 내의 지역변수라고 이해하면 된다. 이름이 같아도 다른 메서드 안에 있기 때문에 완전히 다른 변수다. 즉, main ( )의 number와 changeNumber ( )의 number는 서로 다른 변수이다.

 

 

메서드 호출과 값 반환받기

그렇다면 메서드를 사용해서 값을 변경하려면 어떻게 해야할까?

메서드의 호출 결과를 반환 받아서 사용하면 된다.

package method;

public class MethodValue3 {
    public static void main(String[] args) {
        int num1 = 5;
        System.out.println("1. changeNumber 호출 전, num1: " + num1);
        num1 = changeNumber(num1);
        System.out.println("2. changeNumber 호출 후, num1: " + num1);
    }

    public static int changeNumber(int num2) {
        num2 = num2 * 2;
        return num2;
    }
}

실행 결과

 

꼭 기억하자!

자바는 항상 변수의 값을 복사해서 대입한다.

 

 

5. 메서드와 형변환

메서드를 호출할 때도 형변환이 적용된다.

 

1) 명시적 형변환

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);
    }
}

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을 대입

실행 결과

 

 

2) 자동 형변환

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);
    }
}

int형 인수를 double형 매개변수(파라미터)로 전달하는 데 문제없이 잘 동작한다.

실행 결과

 

[자동 형변환 과정]

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) //자동 형변환 완료

 

정리

메서드를 호출할 때는 전달하는 인수(=인자)의 타입과 매개변수(=파라미터)의 타입이 맞아야 한다.

단, 타입이 달라도 자동 형변환이 가능한 경우에는 호출할 수 있다.

 

 

6. 메서드 오버로딩(method overloading)

메서드 오버로딩(method overloading)이란 같은 이름의 메서드를 중복하여 정의하는 것을 의미한다.

 

자바에서는 원래 한 클래스 내에 같은 이름의 메서드를 둘 이상 가질 수 없다.

하지만 매개변수의 개수나 타입을 다르게 하면, 하나의 이름으로 메서드를 작성할 수 있다.

즉, 메서드 오버로딩은 서로 다른 시그니처를 갖는 여러 메서드를 같은 이름으로 정의하는 것이라고 할 수 있다.

 

메서드 오버로딩을 사용함으로써 메소드에 사용되는 이름을 절약할 수 있다.

또한, 메서드를 호출할 때 전달해야 할 매개변수의 타입이나 개수에 대해 크게 신경을 쓰지 않고 호출할 수 있게 된다.

 

※ 오버로딩(overloading): 과적(過積) - 과하게 물건을 담았다

→ 같은 이름의 메서드를 여러 개 정의했다

 

[오버로딩 성공]

add(int a, int b)
add(int a, int b, int c)
add(double a, double b)

메서드 이름은 같아도 매개변수의 타입 및 개수가 다르기 때문에 오버로딩을 할 수 있다.

 

[오버로딩 실패]

int add(int a, int b)
double add(int a, int b)

반환 타입만 다른 것은 오버로딩을 할 수 없다.

이 케이스는 메서드 이름과 매개변수의 타입 및 개수가 같기 때문에 오버로딩을 할 수 없다. → 컴파일 오류

 

메서드 시그니처(method signature)
메서드 시그니처 = 메서드 이름 + 매개변수 타입(순서 및 개수)

 

메서드 시그니처: 메서드를 구분할 수 있는 고유한 식별자나 서명

 

메서드 오버로딩에서처럼 메서드 이름이 같아도 메서드 시그니처가 다르면 각각 다른 메서드로 간주한다.

반환 타입은 시그니처에 포함되지 않는다.

오버로딩에 실패한 두 메서드를 보면 두 메서드는 add(int a, int b)로 메서드 시그니처가 같기 때문에 메서드의 구분이 불가능하므로 컴파일 오류가 발생한다.

 

 

[오버로딩 예제1: 매개변수의 개수가 다른 경우]

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)가 호출된다.

실행 결과

 

[오버로딩 예제2: 매개변수의 타입이 다른 경우1]

package method;

public class Overloading2 {
    public static void main(String[] args) {
        myMethod(1.2, 1);
        myMethod(1, 1.2);
    }

    public static void myMethod(int a, double b) {
        System.out.println("int a, double b");
    }

    public static void myMethod(double a, int b) {
        System.out.println("double a, int b");
    }
}

1: 실수 1.2, 정수 1을 호출했으므로 myMethod(double a, int b)가 호출된다.

2: 정수 1, 실수 1.2를 호출했으므로 myMethod(int a, double b)가 호출된다.

실행 결과

 

[오버로딩 예제3: 매개변수의 타입이 다른 경우2]

package method;

public class Overloading3 {
    public static void main(String[] args) {
        System.out.println("1: " + add(1, 2));
        System.out.println("1: " + 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)가 호출된다.

실행 결과

 

여기서 만약 다음 첫 번째 메서드를 삭제하면 어떻게 될까?

public static int add(int a, int b){
    System.out.println("1번 호출");
    return a + b;
}

1: int형 정수 1, int형 정수 2를 호출했으므로 자동 형변환이 발생해서 add(double a, double b)가 호출된다.

2: 실수 1.2, 실수 1.5를 호출했으므로 add(double a, double b)가 호출된다.

 

package method;

public class Overloading3 {
    public static void main(String[] args) {
        System.out.println("1: " + add(1, 2));
        System.out.println("1: " + add(1.2, 1.5));
    }

    public static double add(double a, double b) {
        System.out.println("2번 호출");
        return a + b;
    }
}

실행 결과

 

먼저 본인의 타입에 최대한 맞는 메서드를 찾아서 실행하고, 그래도 없으면 형 변환 가능한 타입의 메서드를 찾아서 실행한다.

 

 

※ return의 기능

  1. 클래스 내에서 어떤 메서드가 실행되고 해당 메서드의 실행에 따라 나온 값을 호출한 곳에서 돌려받고자 할 때
    return + 반환하고자 하는 값;
  2. 해당 메서드 실행 중에 특정한 조건에 따라 해당 메서드의 진행을 멈추고 빠져나올 때
    return;

    return 뒤에 코드가 더 있어도 뒤에 있는 코드를 실행하지 않고 종료한다.
    즉, 함수를 종료시키고 함수 자체에서 탈출하면서 return 뒷 줄의 코드들을 실행하지 않는 기능을 한다.

+ Recent posts