20.03 ~ 20.08 국비교육/JAVA

Call by value vs Call by reference

찹키리 2020. 3. 21. 23:51

<Call by value>

 

call by value

호출    값으로
함수   인자가 기본형

 

1) 값에 의한 호출, 변수값이 기본형 데이터인 값으로 호출한다.

2) 실인자(가인자)가 변경되어도 가인자(실인자)에 영향이 없다.★ <---> call by reference

 

 

public int add(int a, int b) -> 가인자 {
return a + b;
}

함수 영역 a  b 가인자

---------------------------------

호출 영역 a  b 실인자

int a = 10;
int b = 20;
add(a, b);
   실인자(main 안의 지역변수)

 

-> a, b -> stack 복사 -> int a, int b -> 처리식(a + b) -> 호출영역 add(a, b) 반환

call by value는 기본적으로 함수를 넣어서 파라미터를 반환하는 거의 모든 것, stack 간의 복사가 이루어진다.

 

 

<예제>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class calc {
    public void add(int kuk, int eng) {
        System.out.println("합계: " + (kuk + eng));
    }
 
    public int sub(int kuk, int eng) {
        return kuk - eng;
    }
 
    public int mul(int kuk, int eng)    {
        return kuk * eng;
    }
 
    public static void main(String[] args) {
        Calc c = new Calc();
 
        int a = 100;
        int b = 200;
        c.add(a, b);
 
        System.out.println("뺀 값: " + c.sub(a, b));
        System.out.println("곱한 값: " + c.mul(a, b));
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

 

 

 

 

<Call by reference>

 

호출 by 참조

 

참조값: 인자가 객체(데이터 타입이 기본형이 아님), 즉 인스턴스인 값.
-> 참조값으로 호출한다. 메소드, 객체로 호출한다.

 

ex.

class Hi -> int a, int b, int c

public Hi add(Hi hi) { // -> Hi라는 클래스를 한꺼번에 던진다
hi.c = hi.a + hi.b
return hi.c;
}

함수 영역
--------------------------hashcode↖

호출 영역

Hi hi = new Hi(); -> heap -> address↖
hi.a = 10;
hi.b = 20;
add(hi);

 

객체를 인자로 준다 -> 해쉬코드만을 가리키고 있다.(가상머신이 쉽게 사용할 수 있는 해쉬코드를 생성해서 그 어드레스를 가리킨다)


★가인자값(호출 받는 쪽)를 바꾸면 실인자값(호출 하는 쪽)도 바뀐다.★

 

 

<예제>

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 
class Pay1 {
    String name = "";
    int pay = 0;
    int comm = 0;
    int tax = 0;
 
    public Pay1(String name, int pay, int comm) {
        this.name = name;
        this.pay = pay;
        this.comm = comm; //전역변수
        comm = 100000//지역변수 ---> 인자 변함
        System.out.println("Pay1 생성자 comm: " + comm);
    }
 
    public void tax() {
        tax = (int)(pay * 0.05);
    }
 
    public int earn() {
        int total = (pay + comm) - tax;
        return total;
    }
}
 
public class Employee {
    public static void main(String args[]) {
        String name = "아로미";
        int pay = 1500000;
        int comm = 200000// ---> 얜 
 
        System.out.println("comm 변수의 초기값: " + comm);
 
        Pay1 p = new Pay1(name, pay, comm);
 
        System.out.println("main 메소드 comm: " + comm); //call by value
        //Pay1 메소드의 인자가 변해도 호출하는 쪽의 인자는 변하지 않는다.
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

call by value

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
 
class Pay2 {
    String name = "";
    int pay = 0;
    int comm = 0;
    int tax = 0;
 
    public Pay2(String name, int pay, int comm) {
        this.name = name;
        this.pay = pay;
        this.comm = comm;
    }
 
    public int tax() {
        tax = (int)(pay * 0.05);
        return tax;
    }
 
    public int earn() {
        int total = (pay + comm) - tax;
        return total;
    }
}
 
class PrintPay2 {
    public static void printPay(Pay2 pay) { //Pay2라는 클래스(객체)를 인자로 사용
        System.out.println("--------------------");
        System.out.println("성명: " + pay.name);
        System.out.println("본봉: " + pay.pay);
        System.out.println("보너스: " + pay.comm);
        System.out.println("세금: " + pay.tax);
        System.out.println("실 수령액: " + pay.earn());
        pay.tax = 5000// ---> 가인자 바뀜
        System.out.println("--------------------");
        System.out.println("pay.hashCode(): " + pay.hashCode());
        //실인자 해쉬코드와 동일함(=p.hashCode())
 
 
 
public class Employee_arg2 {
    public static void main(String args[]) {
        Pay2 p = new Pay2("왕눈이"100001000);
 
        p.tax();
 
        PrintPay2.printPay(p);
        Printpay2.printPay(p);
        System.out.println("p.hashCode(): " + p.hashCode());
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter

call by reference

결과적으로, p = pay

-> 해쉬코드도 동일함

 

*tax값은 첫 번째 출력과 두 번째 출력이 다름

 

 

 

 

<String을 인자로 사용하는 경우>

 

String은 엄밀히 말하면 상수다. 동일한 상수는 한 번만 저장되기 때문에, 동일한 String이 인자로 사용되면 같은 heap영역을 가리키게 된다. 즉, 해쉬코드가 동일하다.

또한, 상수기 때문에 바뀌지 않는다는 속성을 갖는다. 때문에, 기존의 문자열을 변경하는 경우 새로운 상수를 다시 만들어내고, 메모리와 해쉬코드 모두 바뀌게 된다.

 

 


-Basic

 

1)String은 객체형이지만, 인자로 사용되면 call by value로 작동한다.
2)String은 ==로 비교하면 안 된다.
3)equals.()를 사용해 비교한다.
4)문자열이 바뀌면 해쉬코드도 바뀐다 -> 문자열은 상수니까 문자열에 변화를 주면 새로운 상수를 만들어낼 수 밖에 없다.
즉, 메모리가 바뀌기 때문에 해쉬코드도 바뀐다. 메모리 사용의 측면에서는 매우 비효율적이고, 메모리가 아깝다. 권장하는 방법은 아니다.
5)String은 영역에 상관없이 동일한 문자열은 동일한 hashcode를 갖는다.

 

 

 

-심화

 

1)

String str = "홍길동";
String str2 = "홍길동";

str == str2; -> true

String str3 = new String("홍길동");
str == str3; -> false

---> 등치연산자를 사용하면 결과값이 전혀 다르게 나오는 경우가 있기 때문에 equals 함수를 사용해야 한다.
str.equals(str2); -> true
str.equals(str3); -> true

 

 

 

-심화심화

 

1)등치연산자는 값을 비교하는 게 아니라 메모리 영역을 비교한다.
-> 때문에 str, str2는 같고 str3는 다르게 나오는 것(상수 영역 vs heap 영역)

2)String은 객체임을 증명한다. -> hashcode가 존재하기 때문(heap 영역에 메모리 할당)
str, str2, str3 haschcode는 동일하다. 즉 등치연산자는 해쉬코드 비교하는 연산자가 아니다.
★equals는 해쉬코드를 비교, 등치연산자는 address를 비교한다★

 

 

<예제>

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
String, call by valuepackage chapter10;
class GenClass {
    private String name;
    private int num;
 //String을 인자로 사용하는 경우
 
    public GenClass(String a, int b) {
        name = a;
        num = b;
    }
 
    public void rename(String a) {
    String str = a;
    System.out.println("\nrename()--------------------");
    System.out.println("rename(): " + str);
    System.out.println("rename() str.hashCode: " + str.hashCode());
 
    str = str + "★";
    System.out.println("\nrename() 문자열 변경----------");
    System.out.println("rename(): " + str);
    System.out.println("rename() str.haschCode: " + str.hashCode());
    //문자열에 에 다른 문자열을 추가하면 아예 다른 상수 메모리가 생성된다.
    //상수기 때문에. 고로, 해쉬태그도 바뀜
 
    }
}
 
public class NonThread {
    public static void main(String[] args) {        
        GenClass t1 = new GenClass("first"1);
 
        String sc = "대한민국";
        System.out.println("\nrename() rename(sc)후-----");
        System.out.println("main() sc: " + sc);
        System.out.println("main() sc.hashCode: " + sc.hashCode());
 
        t1.rename(sc);
        System.out.println("\nrename() rename(sc)후-----");
        System.out.println("main() sc: " + sc);
        System.out.println("sc.hashCode: " + sc.hashCode());
        //그대로 대한민국 -> 이게 call by value
    }
}
    public static void main(String[] args) {        
        GenClass t1 = new GenClass("first"1);
 
        String sc = "대한민국";
        System.out.println("\nrename() rename(sc)후-----");
        System.out.println("main() sc: " + sc);
        System.out.println("main() sc.hashCode: " + sc.hashCode());
 
        t1.rename(sc);
        System.out.println("\nrename() rename(sc)후-----");
        System.out.println("main() sc: " + sc);
        System.out.println("sc.hashCode: " + sc.hashCode());
        //그대로 대한민국 -> 이게 call by value
    }
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

'20.03 ~ 20.08 국비교육 > JAVA' 카테고리의 다른 글

싱글톤(Singletone pattern), final  (0) 2020.03.22
클래스 JVM 메모리 운영, Static variable과 Method  (0) 2020.03.22
클래스 멤버 메소드  (0) 2020.03.21
클래스 구조  (0) 2020.03.21
배열  (0) 2020.03.21