'생각하는 자바'에 해당되는 글 1건

  1. 2008.08.14 pass by Value 와 pass by Reference
2008. 8. 14. 16:22

pass by Value 와 pass by Reference

출처 : 생각하는 자바

 

 

값에 의한 호출(pass by Value)

다음 예제의 출력 결과는 무엇일까? 출처 생각하는 자바

 

Object5.java

 

public class Object5{

  static void method(int a){                  // x1

    a=20;                                            // x2

  }

  public static void main(String[] args){

    int x=10;

    method(x);                                    // x3

    System.out.println(x);                    // x4

  }

}


 

 

20이 출력될 것이라고 생각하는 독자는 필히 이 예제를 실행해 보자. x4행에서 10이 출력된다. 즉, x의 값이 바뀌지 않았다. x3행에서 method를 호출하면 x1행으로 실행 순서가 이동한다. 변수 a가 만들어지고 a에 x가 대입된다. 즉 a에 10이 대입된다. a와 x는 서로 다른 변수이다. x2행에서 x에 20이 대입되고 method가 끝나서 리턴된다. 메소드가 끝나면 메소드 안에서 만들어진 변수, 즉, 지역변수 a는 소멸된다. 따라서 x의 값은 그대로 10이다.

 

[그림 7-3] pass by Value

 

method를 호출하면 a에 x의 값이 대입된다. 이와 같은 메소드 호출을 '값에 의한 메소드 호출(pass by Value)'이라고 한다. 또는 x의 값이 a에 복사가 된다고 해서 '복사에 의한 호출(pass by Copy)'이라고도 한다.

 

Object6.java

 

public class Object6{

  static void swap(int a, int b){              // x1

    int temp=a;                              // x2

    a=b;                                     // x3

    b=temp;                                 // x4

  }

  public static void main(String[] args){

    int x=10, y=20;

    swap(x, y);                               // x5

    System.out.println(x+" "+y);

  }

}


 

출력 결과

 

10 20


 

 

x1행의 swap 메소드는 두 매개 변수의 값을 서로 교환하는 역할을 하도록 만들어진 메소드이다. 하지만 출력 결과를 보면 x와 y의 값이 바뀌지 않았다. 실행 순서를 따라가 보자. x5행에서 swap을 호출하면 x1행의 a에 10이 대입되고 b에 20이 대입된다. x2행에서 temp에 10이 대입되고 x3, x4행에서 a에는 20이, b에는 10이 대입된다. 따라서 a와 b의 값은 서로 바뀌었다. 하지만 x와 y의 값을 서로 교환하는 코드는 어디에도 없다.

 

메소드 호출 시에 매개변수의 자료형이 기본자료형이면 값에 의한 호출을 한다.

 

 

 

레퍼런스에 의한 호출(pass by Reference)

매개변수가 레퍼런스인 메소드를 호출하는 것을 말한다. 다음 예제를 보자.

 

Object7.java

 

public class Object7{

  static void hi(String name){                      // x1

    System.out.println(name+"씨 안녕하세요?");      // x2

  }

  public static void main(String[] args){

    String chulsu="철수";

    hi(chulsu);                                     // x3

  }

}


 

출력 결과

 

철수씨 안녕하세요?


 

x3행에서 hi를 호출하면 x1행의 name에 chulsu가 대입된다.

 

name = chulsu

 

레퍼런스의 대입이므로 name은 chulsu가 참조하는 객체를 참조한다.

 

[그림 7-4] pass by Reference

 

따라서 x2행을 실행하면 출력 결과와 같이 "철수씨 안녕하세요?"가 출력되는 것이다. 매개 변수가 레퍼런스이면 인수로 넘어오는 객체를 참조한다. 즉 새로운 객체를 만들고 참조하는 것이 아니다. 이런 메소드 호출을 '레퍼런스에 의한 호출'이라고 한다.

 

레퍼런스에 의한 호출을 하면 인수로 넘어오는 객체의 속성 값(멤버 변수의 값)을 변경할 수 있다. 다음 예제를 보자.

 

Object8.java

 

public class Object8{

  private int a;

  public Object8(int a){

    this.a = a;

  }

  public void twice(Object8 o){            // x1

    o.a *= 2;                                      // x2

  }

  public int getA(){

    return a;

  }

  public static void main(String[] args){

    Object8 ob=new Object8(100);             // x3

    ob.twice(ob);                                     // x4

    System.out.println(ob.getA());            // x5

  }

}


 

출력 결과

 

200


 

 

x3행에서 Objcet8의 생성자가 실행되어 'ob.a=100'이 됨을 알 수 있다. x4행에서 twice메소드를 호출하여 x1행의 매개 변수 o가 ob의 객체를 참조한다.

 

[그림 7-5] pass by Reference

 

x2행에서 o.a에 2를 곱하여 'o.a=200'이 된다. ob가 같은 객체를 참조하고 있으므로 ob.a도 200이 됨을 알 수 있다. 따라서 x5행을 실행하면 출력 결과와 같이 200이 출력된다.

 

 

주의하기

 

String형 객체의 문자열은 불변이다.

String s=new String("abcdef");

s가 참조하고 있는 문자열 "abcdef"를 다른 문자열로 바꿀 수 없다. 이유는 String의 멤버 메소드 중에 문자열을 바꾸는 기능을 하는 메소드가 존재하지 않기 때문이다.

 

 

Object9.java

 

public class Object9{

  static void toHello(String s){  // x1

    s="Hello";                   // x2,  's=new String("Hello");' 라고 적어도 된다.

  }

  public static void main(String[] args){

    String hi="Hi";

    toHello(hi);                          // x3

    System.out.println(hi);                 // x4

  }

}


 

출력 결과

 

Hi


 

x3행에서 toHello 메소드를 호출하면 x1행의 s는 hi의 객체를 참조한다. 하지만 x2행에서 다른 객체 "Hello" 객체를 참조하게 된다.

 

[그림 7-6] String 객체의 특성

 

그러나 hi는 여전히 같은 객체를 참조하고 있다. 따라서 x4행에서 hi를 출력하면 "Hi"가 출력된다.

 

메소드의 인자로 레퍼런스뿐만 아니라 새로운 객체를 넘겨 줄 수도 있다. 예제를 보자.

 

Object10.java

 

public class Object10{

  static void play(String name){           // x1

    String a=name+"야 놀자.";             // x2

    System.out.println(a);

  }

  public static void main(String[] args){

    play(new String("철수"));              // x3

  }

}


 

출력 결과

 

철수야 놀자.


 

 

x3행이 실행되면 x1행의 play 메소드의 매개변수 name에게 'new String("철수")'을 넘겨준다. 즉, name은 "철수" 객체를 참조하게 된다. x2행에서 a는 "철수야 놀자." 객체를 참조하게 된다.

'My work space > Java' 카테고리의 다른 글

[아시나요?]JDK  (0) 2008.08.14
[아시나요?] 쓰레드  (0) 2008.08.14
클래스 다이어그램  (0) 2008.08.14
디자인 패턴의 중요성  (0) 2008.08.14
is-a관계  (0) 2008.08.14