티스토리 툴바

블로그 이미지
by 활발한 광식씨

TAG CLOUD

  • 6,098Total hit
  • 1Today hit
  • 5Yesterday hit


컴퓨터 소프트웨어나 하드웨어의 신제품을 시장에 내어 발표하는 것.
TRACKBACK 0 AND COMMENT 0
과거에 개발되어 현재에도 사용 중인 낡은 하드웨어나 소프트웨어. 새로 제안되는 방식이나 기술을 부각시키는 의미로서 주로 사용된다. 예를 들면 시스템이 구축되지 않은 상태에서 새로운 시스템을 구축하면 구축되지 않은 상태가 레거시가 된다. 레거시 프로그램들은 특정 용도나 환경 아래에서만 작동하게 되어 있으나, 최신 프로그램들은 대부분 개방형으로 개발된다.
TRACKBACK 0 AND COMMENT 0
자바에서 모든 파라메터는 Call by Value로 전달됩니다.의외로 이 사실을 헷갈려하는 사람들이 많은데 그 이유는 Reference Type과 Value Type으로 구분되는 자바 Type System 때문입니다.

백문이불여일타:

public class PassingValueType { 
  public static void main(String[] args) { 
    PassingValueType test = new PassingValueType(); 
 
    int anInteger = 1; 
    System.out.println("before: " + anInteger); 
    test.testAssignmentOperation(anInteger); 
    System.out.println("after: " + anInteger); 
  } 
 
  void testAssignmentOperation(int anInteger) { 
    anInteger = 2; 
  } 
} 

결과는 다음과 같습니다:

before: 1 
after: 1 

반면 Basic 같은 언어는 기본적으로 Call by Reference를 사용하기 때문에 위와 같은 코드를 작성하면:

before: 1 
after: 2 
라는 결과가 나옵니다(Basic에서 Call by Value를 사용하려면 byval 키워드를 사용합니다).

int, float, double, char 등과 같은 Value Type에 대해서는 위에서 살펴본 바와 같이 별로 헷갈리는 부분이 없습니다. 문제는 ArrayList, HashMap 등과 같은 Reference Type 들입니다:

import java.util.*; 
 
public class PassingReferenceType { 
  public static void main(String[] args) { 
    PassingReferenceTypetest = new PassingReferenceType(); 
 
    Map aMap = new HashMap(); 
    System.out.println("before: " + aMap.size()); 
    test.testDotOperation(anInteger); 
    System.out.println("after: " + aMap.size()); 
  } 
 
  void testDotOperation(Map aMap) { 
    aMap.put("Key", "Value"); 
  } 
} 

결과는 PassingValueType의 경우와 달리 다음과 같습니다:

before: 0 
after: 1 

이게 어떻게 된걸까요? HashMap과 같은 Reference Type은 Call by Reference라는 얘기일까요? 그렇지 않습니다. Reference Type 역시 Call by Value로 전달됩니다. 다음 코드를 봅시다:

import java.util.*; 
 
public class PassingReferenceType2 { 
  public static void main(String[] args) { 
    PassingReferenceTypetest = new PassingReferenceType(); 
 
    Map aMap = new HashMap(); 
    aMap.put("key", "value"); 
    System.out.println("before: " + aMap.size()); 
    test.testAssignmentOperation(anInteger); 
    System.out.println("after: " + aMap.size()); 
  } 
 
  void testAssignmentOperation(Map aMap) { 
    aMap = new HashMap(); 
  } 

이 코드의 실행 결과는 다음과 같습니다:

before: 1 
after: 1 

PassingReferenceTypePassingReferenceType2의 차이가 뭐길래 이렇게 다른 결과가 나오는걸까요? 차이는 메서드 내부에서 수행된 연산이 대입 연산(Assignment operation)인지, Dot 연산(Dot operation)인지에 있습니다. PassingReferenceType.testDotOperation()에서는 전달된 레퍼런스 변수의 값 자체를 바꾸는게 아니라 레퍼런스 변수가 지칭하고 있는 인스턴스의 메서드를 호출하여(Dot operation) 인스턴스의 내용을 바꾸고 있습니다. 반면 PassingReferenceType2.testAssignmentOperation()에서는 전달된 레퍼런스 변수에 새로운 인스턴스의 레퍼런스 값을 대입(Assignment operation)하고 있습니다.

그럼 파라메터에 대한 대입 연산이 왜 메서드 외부에서는 무시되는 것일까요? 그 이유는 Call by Value의 특성 때문입니다. 변수를 Call by Value로 전달하게 되면 변수가 가지고 있던 값을 복사하여 Stack에 넣게 되고, 호출된 메서드는 이 복사된 값을 다루게 됩니다. 그리고 이 복사된 값은 메서드 실행이 끝나면 사라집니다. 따라서 대입 연산을 아무리 수행해봤자 원래의 변수가 바뀌는 것이 아니라, 메서드 내부에서만 존재하는 복사된 변수가 바뀌는 것입니다. 그럼 String과 같은 Reference Type을 전달하면 그 문자열이 몽땅 복사되니까 비효율적이지 않을까요? 그렇지 않습니다. 복사되는 것은 String 인스턴스가 아니라, String 인스턴스를 가르키고 있는 레퍼런스값이기 때문입니다.

지금까지 설명한 내용을 헷갈리지 않고 이해할 수 있는 쉬운 방법은 "전달 대상"과 "전달 방법"을 구분하는 것입니다. 즉, "무엇을" 전달하는지와 "어떻게" 전달하는지를 구분해야 한다는 것입니다. PassingValueType에서 우리가 전달한 대상은 int 값인 "1"이다. PassingReferenceType에서 전달한 대상은 HashMap 인스턴스에 대한 참조값(Reference)입니다. 전달 방법은 두 경우 모두 Call by Value입니다.

합쳐서 말해보면,

  • PassingValueType에서는 int 값을(무엇을) Call by Value로(어떻게) 전달
  • PassingReferenceType에서는 HashMap 인스턴스의 참조값을(무엇을) Call by Value로(어떻게) 전달

한 것입니다.
TRACKBACK 0 AND COMMENT 0

ARTICLE CATEGORY

KS' LIFE (27)
JAVA (17)
JSP (3)
Servlet (0)
AJAX (0)
JAVA Script (0)
HTML (0)
DBMS (0)
Web Service (5)
Network (0)
용어사전 (2)
ETC (0)
Music Life (0)