[TIL] JAVA - 변수와 메서드 II

MOON·2021년 9월 21일
0

[TIL] JAVA_STUDY

목록 보기
5/20
post-thumbnail

💡Day 06 변수와 메서드 II

이 글은 남궁성님의 자바의 정석 3/e를 기반으로 공부한 내용을 정리한 글입니다.

소스정리: https://github.com/qudalsrnt3x/javaStandard


✏️기본형 매개변수와 참조형 매개변수

기본형 매개변수 변수의 값을 읽기만 할 수 있다. (read only)
참조형 매개변수 변수의 값을 읽고 변경할 수 있다. (read & write)

class PrimitiveParamEx {
	public static void main(String[] args) {
    	Data d = new Data(); // 인스턴스 생성
        d.x = 10; // 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);
    }
    
    static void change(int x) {
    	x = 1000;
        System.out.println("change() : x = " + x);
    }
}

실행결과

main() : x = 10
change() : x = 1000
After chage(d.x)
main() : x = 10

문제점

change메서드에서 main메서드로부터 넘겨받은 d.x의 값을 1000으로 변경했는데도 main메서드에서는 d.x의 값이 그대로다.

  • d.x의 값이 변경된 것이 아니라, change메서드의 매개변수 x의 값이 변경됐기 때문이다.
class Data { int x; }

class ReferenceParamEx {
	public static void main(String[] args) {
    	Data d = new Data();
        d.x = 10;
        System.out.println("main() : x = " + d.x);
        
        change(d);
        System.out.println("After chanage(d)");
        System.out.println("main() : x = " + d.x);
    }
    
    static void change(Data d){ 
    //매개변수가 첨조형이기 때문에 x의 값이 아닌 주소가 매개변수 d에 복사되었다.
    	d.x = 1000;
        // main메서드의 참조변수 d와 change메서드의 참조변수 d는 같은 객체를 가리킨다.
        System.out.println("change() : x = " + d.x);
    }
}

실행결과

main() : x = 10
change() : x = 1000
After change(d)
main() : x = 1000

참조형 매개변수

값이 아닌 '값이 저장된 주소'를 넘겨주면 값을 읽어오는 것뿐만 아니라 변경하는 것도 가능하다.

class ReferenceOaranEx2 {
	public static void main(String[] args) {
    	int[] x = {10}; // 크기가 1인 배열. x[0] = 10;
        System.out.println("main() : x = " + x[0]);
        
        change(x);
        System.out.println("After change(x)");
        System.out.println("main() : x = " + x[0]);
    }
    
    static void change(int[] x) {
    	x[0] = 1000;
        System.out.println("change() : x = " + x[0]);
    }	
}

실행결과

main() : x = 10
change() : x = 1000
After change(x)
main() : x = 1000

배열도 객체와 같이 참조변수를 통해 데이터가 저장된 공간에 접근하기 때문에 참조형 매개변수와 같은 결과를 얻을 수 있다.

임시적으로 간단히 처리할 때는 별도의 클래스를 선언하는 것보다 이처럼 배열을 이용할 수도 있다.


✏️참조형 반환타입

매개변수뿐만 아니라 반환타입도 참조형이 될 수 있다.

반환타입이 참조형이라는 것은 메서드가 '객체의 주소'를 반환한다는 것을 의미한다.


✏️재귀호출(recursive call)

메서드의 내부에서 메서드 자신을 다시 호출하는 것을 '재귀호출'이라 한다.

void method() {
	method(); // 재귀호출. 메서드 자신을 호출한다.
}

조건문과 함께

오로지 코드가 재귀호출 뿐이라면, 무한반복에 빠지게 된다. 무한반복부이 조건문과 함께 사용되어야하는 것처럼, 재귀호출도 조건문이 필수적으로 따라다닌다.

void method(int n) {
    if(n == 0) 
    	return; // n의 값이 0일 때, 메서드를 종료한다.
    System.out.println(n);
    
    method(--n); // 재귀호출. method(int n)을 호출
} 

재귀호출과 반복문

재귀호출은 반복문과 유사한 점이 많으며, 대부분의 재귀호출은 반복문으로 작성하는 것이 가능하다.

반복문보다 재귀호출의 수행시간이 더 오래 걸린다.

  • 왜 굳이 반복문대신 재귀호출을 사용할까?
    논리적 간결함 때문

대표적인 재귀호출의 예시 팩토리얼(factorial)

f(n) = n * f(n-1), 단 f(1) = 1

class FactorialTest {
	public static void main(String args[]) {
    	int result = factorial(4);
        
        System.out.println(result);
    }
    
    static int factorial(int n) {
    	int result = 0;
        
        if(n == 1)
        	result = 1;
        else
        	result = n * factorial(n-1); // 다시 메서드 자신을 호출한다.
            
        return result;
    }
    
}

만일 factorial메서드의 매개변수 n의 값이 0이면??

'호출하는 사람이 당연히 알아서 적절한 값을 인자로 주겠지.' 라는 막연한 믿음을 가져서는 안 된다. 매개변수의 유효성검사는 중요하다.


✏️클래스 메서드(static메서드)와 인스턴스 메서드

인스턴스 메서드는 인스턴스 변수와 관련된 작업을 하는, 즉 메서드의 작업을 수행하는데 인스턴스 변수를 필요로 하는 메서드이다.

반면에 메서드 중에서 인스턴스와 관계없는(인스턴스 변수나 인스턴스 메서드를 사용하지 않는) 메서드를 클래스 메서드(static메서드)로 정의한다.

어떤 경우에 인스턴스 메서드, 클래스 메서드를 사용해야 할까?

  • 클래스를 설계할 때, 멤버변수 중 모든 인스턴스에 공통으로 사용하는 것에 static을 붙인다.
    모든 인스턴스에서 같은 값이 유지되어야 하는 변수는 static을 붙여서 클래스변수로 정의해야 한다.

  • 클래스 변수는 인스턴스를 생성하지 않아도 사용할 수 있다.

  • 클래스 메서드(static메서드)는 인스턴스 변수를 사용할 수 없다.
    클래스 메서드가 호출되었을 때 인스턴스가 존재하지 않을 수도 있다.

  • 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려한다.
    메서드 호출시간이 짧아지므로 성능이 향상된다.

고려사항

  • 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야하는 것이 있는지 살펴보고 있으면, static을 붙여준다.

  • 작성한 메서드 중에서 인스턴스 변수나 인스턴스 메서드를 사용하지 않는 메서드에 static을 붙일 것을 고려한다.

  • 클래스안에 멤버변수를 사용하지 않는 메서드(매개변수만 받는 메서드)에는 static을 붙일 것을 고려한다.

예제를 통해 어떤 경우 인스턴스메서드로, 또는 클래스메서드로 선언해야하는지 확인

class MyMath2 {
	long a, b;
    
    // 인스턴스변수 a, b만을 이용해서 작업하므로 매개변수가 필요없다.
    long add() { return a + b; }
    long subtract() { return a - b; }
    long multiply() { return a * b; }
    double divide() { return a / b; }
    
    // 인스턴스변수와 관계없이 매개변수만으로 작업이 가능하다.
    static long add(long a, long b) { return a + b; }
    static long subtract(long a, long b) { return a - b; }
    static long multiply(long a, long b) { return a * b; }
    static double divide(double a, double b) { return a / b; }
}

public class MyMathTest2 {
	public static void main(String[] args) {
    	// 클래스메서드 호출, 인스턴스 생성없이 호출가능
        System.out.println(MyMath2.add(200L, 100L));
        System.out.println(MyMath2.subtract(200L, 100L));
        System.out.println(MyMath2.multiply(200L, 100L));
        System.out.println(MyMath2.dvide(200.0, 100.0));
        
        MyMath2 mm = new MyMath2(); // 인스턴스를 생성
        mm.a = 200L;
        mm.b = 100L;
        
        // 인스턴스메서드는 객체생성 후에만 호출이 가능함
        System.out.println(mm.add());
        System.out.println(mm.subtract());
        System.out.println(mm.multiply());
        System.out.println(mm.divide());
    }
}

실행결과

300
100
20000
2.0
300
100
20000
2.0

0개의 댓글