[F-Lab 모각코 챌린지 5일차] Call by Value, Call by Reference in Java/어노테이션
TIL
- Call by Value, Call by Reference in Java
- 어노테이션
Call by Value, Call by Reference in Java
Call by Value
메소드의 매개변수에서 값을 복사하느냐 주소값을 참조하느냐의 개념이다. Call by Value는 더 정확히 말하자면 값만 복사하여 전달한다는 개념이다. 호출 된 메소드에서 전달 받은 매개변수를 어떻게 지지고 볶던 호출 한 메소드가 가지고 있던 원래 값은 변하지 않는다.
public class Main {
public static void main(String[] args) {
int a = 50;
int b = 100;
callByValue(a, b);
System.out.println(a); // 50
System.out.println(b); // 100
}
static void callByValue(int a, int b) {
a = 51;
b = 101;
System.out.println(a); // 51
System.out.println(b); // 101
}
}
위 코드를 보면 main()
메소드에서 callByValue()
메소드를 호출하면서 매개변수로 정수값(a, b)을 넘겼다. callByValue()
메소드에서 전달 받은 매개변수의 값을 변경한다. 이때 main()
메소드에 존재하는 a, b 변수의 값들이 변경됐을까? 아니다. main()
메소드에 존재하는 a, b 변수의 값들은 여전히 그대로다. callByValue()
메소드는 main()
메소드로부터 매개변수 값을 복사하여 전달 받은 것이기 때문에 두 영역의 변수는 서로 완전히 남남이다.
Call by Reference
public class Main {
public static void main(String[] args) {
int[] a = { 1 };
callByReference(a);
System.out.println(a[0]); // 22
}
static void callByReference(int[] a) {
a[0] = 22;
System.out.println(a[0]); // 22
}
}
Call by Reference는 객체에 대한 참조를 전달한다는 의미이다. Call by Reference로 값이 전달되면 호출한 메소드의 데이터에도 영향을 준다. callByReference()
메소드를 호출하면 int 배열의 참조값이 복사되어 매개변수(int[] a
)로 넘겨진다. 따라서 main()
메소드 안에 a 변수와 callByReference()
메소드 안에 a 변수가 똑같은 주소값을 들고 있게 된다. 이 주소가 가리키는 메모리의 위치는 똑같기 때문에 두 변수가 하나의 데이터를 동시에 참조하고 있다.
callByReference()
메소드 내에서 해당 배열의 첫번째 요소 값을 바꾸고 main()
메소드 내에서 a[0] 값을 출력해보면 바뀐 값으로 나온다는 것을 알 수 있다. 이처럼 매개변수로 객체에 대한 참조를 넘길 경우, 객체 상태를 변경한 결과에 영향을 받게 된다.
그런데 자바에는 Call by Reference 라는 개념이 없다.
왜냐하면 자바에서는 개발자가 직접 메모리 주소에 접근 하지 못하도록 설계했기 때문이다. 자바에서의 파라미터는 오직 Call by Value로서만 동작된다. 호출 된 메소드로 기본자료형이 복사되느냐, 객체에 대한 참조값이 복사되느냐의 차이만 있을 뿐이다.
C언어의 포인터 개념을 잘 몰라서 Call by Reference 개념이 헷갈리는데 나름 추측해보자면,
public class Main {
public static void main(String[] args) {
int[] a = { 1 };
callByReference(a);
System.out.println(a[0]); // 1
}
static void callByReference(int[] a) {
a = new int[3]();
a[0] = 500;
System.out.println(a[0]); // 500
}
}
callByReference()
메소드에 선언 된 매개변수 a는 복사 된 참조값이기 때문에 내부에서 새 배열을 생성하고 값을 조작했을 때 main()
메소드 내부에 있는 a 변수에 아무런 영향도 주지 못한다. 즉, 호출 된 메소드 내에서 값을 변경했지만 호출 한 메소드에 있는 값은 변경 되지 않았다. 그렇게 때문에 Call by Value라고 생각했다.
C언어의 Call by Reference
#include <stido.h>
void swap(int *, int *);
int main() {
int a = 10;
int b = 20;
swap(&a, &b); // &: 주소 연산자
}
void swap(int *a, int *b) { // *: 포인터 변수
int temp;
temp = *a;
*a = *b;
*b = temp;
}
ℹ swap() 함수 코드 과정 도식화




위 코드와 같이 C언어에서는 함수를 호출할 때 주소연산자(&)로 주소값을 직접 넘겨주고 포인터(*) 변수를 파라미터로 받게 하면 직접적인 메모리 참조가 가능하다. swap()
함수 내 변수들은 포인터 변수이기 때문에 메모리 주소를 직접 참조해서 이 함수를 호출한 main()
함수 내의 변수 a, b 값을 변경해버린다.
어노테이션
어노테이션은 클래스나 메소드, 변수 등의 선언 시에 @를 사용하는 것을 말하며 메타데이터라고 부르기도 한다.
어노테이션은 왜 사용할까?
- 컴파일러에게 정보를 알려줄 때
- 컴파일 할 때와 deployment 시의 작업을 지정할 때
- 실행 시 별도의 처리가 필요할 때
어노테이션의 종류
- 자바 언어에서 사용하기 위해 정해져 있는 어노테이션 3개
- @Overried
- @Deprecated
- @SupressWarnings
- 어노테이션을 선언하기 위한 메타 어노테이션 4개
- @Target
- @Retention
- @Documented
- @Inherited
일반적으로 사용 가능한 어노테이션
@Overried
- 해당 메소드가 부모 클래스에 있는 메소드를 Override 했다는 것을 명시적으로 선언
- Override를 할 때, 부모 클래스에 있는 메소드명과 매개변수들을 동일하게 가져간다. 해당 메소드는 Override 된 거니까 부모 클래스에 있는 메소드명, 매개변수가 다를 시 컴파일러가 알려주도록 지정해주는 역할을 한다. 그렇기 때문에 부모 클래스의 메소드를 제대로 Override 했는지 확인하는 수단으로 사용할 수 있다.
@Deprecated
- 클래스나 메소드가 더 이상 사용되지 않는 경우, 이 요소는 더이상 사용하지 않는 것이라고 컴파일러가 경고 알림을 해주는 역할이라고 보면 된다.
@SupressWarnings
- 간혹 컴파일러가 경고를 알리는 경우가 있는데 그 경고 알림을 끄는 역할을 해준다.
- 해당 어노테이션을 남용할 경우, Deprecated 된 메소드를 사용해도 컴파일러의 경고가 없어 모르고 넘어갈 수도 있으니 유의해야한다.
메타 어노테이션
@Target
어노테이션을 어떤 요소에 적용할 지 선언할 때 사용한다.
@Retention
어노테이션 정보가 얼마나 오래 유지되는지를 선언할 때 사용한다.
요소 | 대상 |
---|---|
SOURCE | 어노테이션 정보가 컴파일 시, 사라진다. |
CLASS | 클래스 파일에 있는 어노테이션 정보가 컴파일러에 의해 참조 가능하다. 하지만 JVM에서는 사라진다. |
RUNTIME | 실행 시, 어노테이션 정보가 JVM에 의해 참조 가능하다. |
@Documented
해당 어노테이션에 대한 정보가 Javadocs(API) 문서에 포함된다는 것을 선언한다.
@Inherited
모든 자식 클래스에서 부모 클래스의 어노테이션을 사용 가능하다는 것을 선언한다.
@interface
어노테이션을 선언할 때 사용한다.
어노테이션 선언
@Target(ElementType.METHOD) // 해당 어노테이션의 사용대상을 (메소드에 사용할 수 있음)
@Retention(RetentionPolicy.RUNTIME) // 어노테이션 유지 정보 (실행 시, VM이 이 어노테이션 참조)
public @interface UserAnnotation {
public int number();
public String text() default "This is first annotation";
}
public class UserAnnotationEx {
@UserAnnotation(number=0, text="annotation example")
public static void main(String[] args) {
}
}
어노테이션 제약사항
어노테이션을 선언할 때, 미리 만들어놓은 어노테이션을 확장하는 것은 불가능하다. 즉, extends 예약어를 사용할 수 없다.
📚 참고
자바의 신
☕ 자바는 Call by reference 개념이 없다 ❓
C 언어 Call-by-Value(값에 의한 호출) & Call-by-Reference(참조에 의한 호출)의 이해
'JAVA' 카테고리의 다른 글
[F-Lab 모각코 챌린지 7일차] Generics (1) | 2023.06.14 |
---|---|
[F-Lab 모각코 챌린지 6일차] equals(), hashCode() (0) | 2023.06.13 |
[F-Lab 모각코 챌린지 4일차] Garbage Collector (0) | 2023.06.11 |
JVM 메모리 구조 (2) | 2023.06.10 |
[F-Lab 모각코 챌린지 2일차] 자바의 구동방식/Class Loader, Nested Class (0) | 2023.06.09 |
댓글
이 글 공유하기
다른 글
-
[F-Lab 모각코 챌린지 7일차] Generics
[F-Lab 모각코 챌린지 7일차] Generics
2023.06.14 -
[F-Lab 모각코 챌린지 6일차] equals(), hashCode()
[F-Lab 모각코 챌린지 6일차] equals(), hashCode()
2023.06.13 -
[F-Lab 모각코 챌린지 4일차] Garbage Collector
[F-Lab 모각코 챌린지 4일차] Garbage Collector
2023.06.11 -
JVM 메모리 구조
JVM 메모리 구조
2023.06.10