클래스란 무엇인가? 6 : 메서드/생성자 전달

정소이·2023년 1월 20일
0

OOP를 향해서

목록 보기
8/10

메서드, 생성자에 대한 선언: 해당 메서드와 생성자에 대한 인자를 선언하는 것이다.

예를 들어, 대출 금액, 이자율, 대출 기간 및 미래 가치를 기반으로 주택 대출에 대한 월 금액을 계산하는 메서드를 보자.

	public double computePayment(
    				double loanAmt,
                    double rate,
                    double featureValue,
    				int numPeriods)
    ){
    	double interest = rate /100.0;
        double partiall = Math.pow((1 + interest),
        				- numPeriods);
        double demonimator = (1 - partiall) / interest;
        double answer = (-loanAmt / denominator)
        				- ((futureValue * partiall) / denominator);
        return answer;
    }

이 메서드는 파라미터를 네개 갖고있다. 대출 금액, 이자율, 미래 가치 및 대출 기간.
처음 세개는 double, float 타입 숫자들이고 마지막은 integer 타입이다.
이 파라미터들은 메서드 바디 내에서 사용되고 런타임에 전달된 인수를 사용한다.

파라미터들은 메서드 선언에서 변수 목록을 나타낸다. 인수(Arguments)는 메서드가 호출 될 때 전달되는 실제 값이다. 메서드를 호출할 때, 인수는 선언의 매개변수와 타입과 순서가 일치해야 한다.


파라미터 타입

메서드나 생성자의 파라미터는 모든 데이터 타입을 사용할 수 있다. 여기에는 위 메서드에서 본것처럼, double, float, integer같은 기본타입과 objects와 arrays 같은 참조 데이터가 포함된다.

아래 인자로 배열을 받는 메서드 예제가 있다. 이 예제에서 메서드는 Polygon 객체를 생성하고 Point라는 객체의 배열을 인수로 받아 초기화한다.(Point를 x,y 좌표를 나타내는 클래스로 가정한다.)

	public PolygonFrom(Point[] corners) {
    	// 메서드 바디는 여기 위치한다.
    }

만약 메서드 안으로 메서드를 전달하고 싶다면, 람다식이나 메서드 참조를 사용한다.

인자(Arguments)의 임의 갯수 : varargs

varargs 라는 생성자를 이용하면 메서드에 임의의 갯수 값을 전달할 수 있다. varargs 는 특정 타입의 인자가 메서드에 전달될지 모를 때 사용한다. 이건 배열을 수동으로 생성할 수 있는 지름길이다.

varargs를 사용하기위해, 줄임표(...)와 공백, 파라미터 이름으로 된 마지막 파라미터를 따른다. 이 메서드는 none을 포함해서 해당 파라미터를 사용해 메서드를 호출할 수 있다.

	public Polygon polygonFrom(Point... corners) {
    	int numberOfSides = corners.length;
        double squareOfSide1, lengthOfSide1;
        squareOfSide1 = (corners[1].x - corners[0].x)
        				* (corners[1].x - corners[0].x)
                        + (corners[1].y - corners[0].y)
                        * (corners[1].y - corners[0].y);
        lengthOfSide1 = Math.sqrt(squareOfSide1);
        
        // more method body code follows that creates and returns a 
	    // polygon connecting the Points
    }

메서드 안에서, corners가 배열로 관리됨을 볼 수 있다. 이 메서드는 배열이나 일련의 인자로 호출될 수 있다. 이 메서드의 코드는 두 경우 모두(배열이나 일련의 인자로 호출) 매개 변수를 배열로 처리할 것이다.

pringing 메서드에서 varags를 쉽게 볼 수 있다. (예: printf) :


    	public PrintStream printf(String format, Object... args)
    

임의의 갯수의 객체를 인쇄하고 싶다면 다음과 같이 호출한다. :

    	System.out.printf("%s: %d, %s%n", name, idnum, address);

또는

		System.out.printf(%s: %d:, %s, %s%n", name, idnum, address, phone, email);

또는 아직 다른 인자가 있다.


매개변수(Parameter) 이름

메서드나 생성자의 매개변수를 선언할 때 해당 매개변수의 이름을 제공한다. 이 이름은 전달된 인자를 참조하기 위해 메서드 바디 안에서 사용된다.

파라미터 이름은 해당 범위에서 반드시 유니크해야한다. 같은 메서드나 생성자의 다른 파라미터와 같은 이름이 될 수 없고, 메서드와 생성자 내부의 지역변수 이름일 수 없다.

이 파라미터는 클래스의 필드중 하나와 같은 이름을 가질 수 있다. 이 경우엔 shadow the field 라고 한다. Shadowing fields 는 코드를 읽기 어렵게 만들고 일반적으로 특정 필드를 설정하는 생성자와 메서드 내에서만 사용한다.
예를 들자.

	public class Circle {
    	private int x, y, radius;
        public void setOrigin(int x, int y) {
        ...
        }
    }

Circle 클래스는 필드 세개(x, y, radius)가 있다. setOrigin 메서드는 파라미터가 두개 있고, 필드 중 같은 이름이 있다. 각 메서드 파라미터는 이름을 공유하는 필드를 shadows 한다. 따라서 x,y같은 심플한 이름은 메서드 파라미터를 참조하고, 필드는 하면 안된다. 필드에 접근하려면, 정규화된 이름을 사용해야한다. 이 주제는 키워드 사용에서 다시 다룬다.


기본 데이터타입 인자 전달

int나 double같은 기본인자는 value 로 메서드에 전달된다. 즉, 파라미터 값들에 대한 모든 변경사항은 메서드 내에서만 유효하다. 메서드가 리턴될 때, 파라미터는 사라지고 파라미터에 대한 변경사항이 사라진다.

package arguments;

public class PassPrimitiveByValue {

    public static void main(String[] args) {

        int x = 3;

        // invoke passMethod() with
        // x as argument
        passMethod(x);

        // print x to see if its
        // value has changed
        System.out.println("After invoking passMethod, x = " + x);

    }

    // change parameter in passMethod()
    public static void passMethod(int p) {
        p = 10;
        System.out.println("After invoking passMethod, p = " + p);
    }
}

결과는 아래와 같다.

After invoking passMethod, p = 10
After invoking passMethod, x = 3

passMethod 내부의 파라미터 p 에 대한 값 10은 메서드가 종료되면서 사라지고 x만 남게 되었다.


참조 데이터타입 인자 전달

Object같은 참조 데이터 타입또한 메서드에 value 에 의해 전달된다. 즉, 메서드가 리턴되면 전달된 참조는 전과 동일한 객체를 참조한다.
그러나 객체 필드 값들은 적절한 접근 레벨에서 메서드 내에서 변할 수 있다.

예를 들어, Circle 객체를 움직이는 임의 클래스의 메서드를 보자.

public void moveCircle(Circle circle, int deltaX, int deltaY) {
    // code to move origin of circle to x+deltaX, y+deltaY
    circle.setX(circle.getX() + deltaX);
    circle.setY(circle.getY() + deltaY);
        
    // code to assign a new reference to circle
    circle = new Circle(0, 0);
}

그리고 다음 인자로 메서드를 호출한다.

moveCircle(myCircle, 23, 56)

메서드 내부에 circle 은 myCircle을 참조한다. 이 메서드는 circle의 참조 객체, 즉 myCircle의 x,y 좌표를 23, 56으로 변경한다. 이 변화는 메서드가 리턴될 때도 유지된다. 그러면 circle은 새 Circle 객체에 대한 참조가 할당된다(x = y = 0). 그러나, 참조가 value로 전달되었고, 변경할 수 없기 때문에 이 재할당은 영구적이지 않다. 메서드 내에서, circle을 가리키는 객체는 변했지만, 메서드가 리턴될 때 myCircle은 메서드 호출 전과 같이 여전히 같은 Circle 객체를 참조한다.

출처
https://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html

profile
프로그래밍 학습에 왕도는 없다! 내가 컴퓨터를 닮아갈때까지!

0개의 댓글