본문 바로가기

카테고리 없음

2021년 10월 9일 (토)

어느 순간부터인가 글을 잘 쓰는 사람이 부러웠다.

자신의 생각을 잘 정리할 수 있는 사람들이 부러웠고, 그러한 능력은 앞으로 살아감에 있어서 더욱더 중요해질 것이라고 생각하였다.

중요성을 깨닫고 오래전 부터 글을 쓰면서 연습을 하려 하였지만, 미루다 보니 어느덧 21년 10월이 되었다.

 

그러던 오늘 작가 '이슬아'님의 기사를 읽게 되었다.

 

"종종 게으른 마음이 드는데, 그런 상태에선 무언가를 대충 보고, 누군가에 대해 빠르게 판단하고 대상을 함부로 단정 짓게 됩니다.
하지만 글을 쓰다 보면 무심히 지나쳤던 것을 다시 보게 되고, 스치듯 지나치던 대화도 잘 기억하게 되어 마음을 부지런하게 쓰게 됩니다."

 

위 구절이 너무나 마음에 와 닿았다.

글을 쓰는 것이 너무 거창해 보여서, 어떻게 써야 할 지 몰라서 계속 미루던 일을 오늘은 꼭 해야할 것 같은 느낌이 들어 바로 컴퓨터를 키고 무엇이라도 적어보자고 생각하였다.

 

오늘은 내가 배운 내용을 정리하는 시간을 갖고자 한다.

부지런하지 못하여, 글로 남기지 않았던 내용을 오늘에서야 시작해 본다.

 

Call by Value vs Call by Reference

오늘은 Call by value와 Call by reference 개념에 대한 것이다.

 

Call by Value는 함수의 인자를 전달할 때 '값을 전달하는 방식'이고
Call by Reference는 '주소를 전달하는 방식'이다.

 

 

call-by-value (값에 의한 호출)

  • 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성된다. (c++의 경우 stack frame) 함수가 종료되면 해당 공간은 사라진다.
  • 스택 프레임(Stack Frame) : 함수 호출시 할당되는 메모리 블록(지역변수의 선언으로 인해 할당되는 메모리 블록)
  • call-by-value 값에 의한 호출방식은 함수 호출시 전달되는 변수의 값을 복사하여 함수의 인자로 전달한다.
  • 복사된 인자는 함수 안에서 지역적으로 사용되는 local value의 특성을 가진다.
  • 따라서 함수 안에서 인자의 값이 변경되어도, 외부의 변수의 값은 변경되지 않는다.
  • Java의 경우 함수에 전달되는 인자의 데이터 타입에 따라서 (원시자료형 / 참조자료형) 함수 호출 방식이 달라진다.
    • 원시 자료형 (primitive type) : call-by-value 로 동작 (int, short, long, float, double, char, boolean )
    • 참조 자료형 (reference type): call-by-reference 로 동작 (Array, Class Instance)

 

call-by-reference (참조에 의한 호출)

  • 함수가 호출될 때, 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성된다. (예: stack frame) 함수가 종료되면 해당 공간은 사라진다.
  • call-by-reference 참조에 의한 호출방식은 함수 호출시 인자로 전달되는 변수의 레퍼런스를 전달한다. (해당 변수를 가르킨다.)
  • `따라서 함수 안에서 인자의 값이 변경되면, 아규먼트로 전달된 객체의 값도 함께 변경된다.

 

Call-by-value

Call by Value에 대표적인 예를 먼저 살펴보겠다.

swap 메서드에서 a와 b의 값을 변경하였지만 swap 메서드가 끝난 후 main에 존재하는 a, b 변수의 값은 변하지 않은 것을 확인할 수 있다.

위에서 설명한 call-by-value 특성 때문입니다.

함수 안에서 지역적으로 사용되는 local value의 특성을 가지기에 함수 안에서 인자의 값이 변경되어도, 외부의 변수의 값은 변경되지 않기 때문이다.

 

class Test1 {
    private static void swap(int a, int b) {
        int temp = a;
        a = b;
        b = temp;
    }

    public static void main(String args[]) {
        int a = 1;
        int b = 2;

        System.out.println("a => " + a);
        System.out.println("b => " + b);

        swap(a, b);

        System.out.println("------- swap 후 -------");

        System.out.println("a => " + a);
        System.out.println("b => " + b);
    }
}

 

Call-by-reference

Call-by-reference에 대한 예를 살펴 보겠다.

 

10점을 가지고 있는 객체를 만들었다.

newTest라는 메서드에서 score라는 변수에 5점을 가지고 있는 새로운 객체를 할당하였다.

위에서 Call-by-reference 개념과 같이 함수 안에서 값이 변하였기 때문에, 당연히 newTest 메서드가 끝난 후에도 5점을 가지고 있을 것이라고 생각하였는데, 결과는 다르게 나타난걸 확인할 수 있다.

 

왜?

우선 Java는 Call-by-reference를 사용하지 않는다고 한다.

아래의 개념을 이해하기 위해서는 newTest의 score와 main의 score는 다르다고 생각하면 되겠다.

Call-by-value 개념에서 말씀해 드렸던 것 처럼 지역변수라고 생각하면 될 것 같다.

자신이 새롭게 생성한 지역 변수 main 변수 이름과 변수 값을 복사하여 사용하는 것이다.

public class Test3 {
    public static void main(String[] args) {
        Score score = new Score(10);
        System.out.println(score.getScore());
        newTest(score);
        System.out.println("------- score 수정 -------");
        System.out.println(score.getScore());
    }

    public static Score newTest(Score score) {
        score = new Score(5);
        return score;
    }
}

class Score {
    private int score;

    public Score(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

// 결과
// 10
// ------- score 수정 -------
// 10

 

하지만 값이 변하는 경우도 존재한다.

바로 참조하고 있는 주소에 존재하는 값을 직접 변경하는 경우이다.

 

10점을 가지고 있는 객체를 만들었다.

이번에는 newTest라는 메서드에서 score라는 변수에 5점을 가지고 있는 새로운 객체를 할당하는 대신

score 주소로 직접 들어가 10점을 5점으로 변경하였다.

결과 값을 살펴보면 newTest라는 메서드를 벗어난 후에도 score 객체의 값이 5점인 것을 확인할 수 있다.

public class Test4 {
    public static void main(String[] args) {
        Score score = new Score(10);
        System.out.println(score.getScore());
        newTest(score);
        System.out.println("------- score 수정 -------");
        System.out.println(score.getScore());
    }

    public static Score newTest(Score score) {
        score.setScore(5);
        return score;
    }
}

class Score {
    private int score;

    public Score(int score) {
        this.score = score;
    }

    public void setScore(int score) {
        this.score = score;
    }

    public int getScore() {
        return score;
    }
}

// 결과
// 10 
// ------- score 수정 -------
// 5

 

https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

위 게시글에서 가장 추천 수가 많았던 댓글에서는 이렇게 말한다.

 

자바는 항상 pass by value다.

불행하게도, 객체를 전달할 때 Reference를 전달하는데 이것은 초보자들을 헷갈리게 한다고 한다.

 

요약해보면

자바는 Call-by-value 이지만 그렇지만 주소를 타고 가서 값을 직접 변경하는 것 (setter를 이용)은 가능하다.

 

 

참고 블로그

https://devlog-wjdrbs96.tistory.com/44

 

[JAVA] Call by Value 와 Call by reference 란 ?

C언어를 주로 공부 했던 나는 Call by value 와 Call by reference 에 대해서 call by value 는 값을 넘기는 거고 call by reference 는 포인터를 이용해서 주소를 넘긴다고 알고 있다. 하지만 누군가 나에게 이..

devlog-wjdrbs96.tistory.com

https://velog.io/@ahnick/Java-Call-by-Value-Call-by-Reference

 

[Java] Call by Value, Call by Reference

프로그래밍 언어들의 메소드 매개변수 호출 방식에는 여러 가지가 있으며 호출 방식은언어마다 다르게 되어 있습니다. 그 중 자바의 Call by Value 방식에 대해 알아봅시다 !

velog.io

https://wayhome25.github.io/cs/2017/04/11/cs-13/

 

강의노트 12. 함수 호출방식(call-by-value, call-by-reference, call-by-assignment) · 초보몽키의 개발공부로그

패스트캠퍼스 컴퓨터공학 입문 수업을 듣고 중요한 내용을 정리했습니다. 개인공부 후 자료를 남기기 위한 목적임으로 내용 상에 오류가 있을 수 있습니다.

wayhome25.github.io

https://nowonbun.tistory.com/303

 

[Java] 10. 메모리 할당(stack 메모리와 heap 메모리 그리고 new)과 Call by reference(포인터에 의한 참조)

안녕하세요. 명월입니다. 이 글은 Java에서 메모리 할당(stack 메모리와 heap 메모리 그리고 new)과 Call by reference(포인터에 의한 참조)에 대한 글입니다. 이전에 제가 클래스를 설명한 적이 있습니다.

nowonbun.tistory.com

https://dublin-java.tistory.com/33

 

Java는 Call by Value? Call by Reference?

얼마 전에 같이 공부하는 형이 갑자기 물어봤다. 자바는 call by value와 call by reference중 어떤 게 맞을까? 그 때 형이 내린 결론은 '자바는 call by value지만 이걸 굳이 나누는 것은 무의미한 거 같다.

dublin-java.tistory.com