객체를 직접 호출하는 것과 인스턴스를 호출하는것의 차이 (메모리 주소값 비교)

객체지향에 대해서 정확히 이해하고 있지 못한것 같아서 인프런에서 객체지향 프로그래밍 입문와 생활코딩에서 JAVA 객체지향 프로그래밍 수업을 정주행하다가 정리한다. 10분 짜리 영상을 정말 거의 10번 가까이 재생하면서 계속 이해하려고 노력했고, 그러고나서도 다시 포스팅하려고 하니까 더 긴 시간이 걸렸다. 하지만 이렇게 정리하고 나니까 조금 뿌듯하다 :)

그동안은 외부 클래스의 메서드를 사용하기 위하여 항상 인스턴스를 생성했었는데, 메서드가 static으로 선언되어 있다면, 인스턴스 생성없이도 해당 객체를 직접 호출해서 사용할 수 있었다. 사실 작성하고 나니 당연한 것이었는데, 그동안 별 생각없이 인스턴스만 생성해서 사용했던것 같다.

두 개의 클래스 파일을 생성해보았다. 하나는 객체를 담았고, 하나는 콘솔로 출력하기 위한 클래스이다.

exam.class

1
2
3
4
public class exam {
public static String classVar = "class 변수";
public String instanceVar = "instance 변수";
}

classVar는 static으로 선언한 변수이고, instanceVar는 키워드 없이 생성한 변수이다.

Main.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Main {
public static void main(String[] args) {
// 인스턴스 생성
exam ex1 = new exam();
exam ex2 = new exam();

System.out.println("ex1.instanceVar : "+ex1.instanceVar);
System.out.println("ex2.instanceVar : "+ex2.instanceVar);

ex1.instanceVar = " changed by instance";
System.out.println("ex1.instanceVar : "+ex1.instanceVar);
System.out.println("ex2.instanceVar : "+ex2.instanceVar);
}
}

exam 클래스로부터 두개의 인스턴스를 생성했고, 그 중 ex1 인스턴스의 변수만 값을 변경해보았다. 출력 결과는 다음과 같다.

1
2
3
4
5
// 출력 결과
ex1.instanceVar : instance 변수
ex2.instanceVar : instance 변수
ex1.instanceVar : changed by instance
ex2.instanceVar : instance 변수

ex1.instanceVar 값을 변경하고, ex1과 ex2의 instanceVar을 각각 출력해봤더니 ex1에만 변경된 값이 적용된걸 알 수 있다.

이를 통해 인스턴스를 생성하면 같은 객체로부터 생성되었다하더라도 바라보는 주소값이 다르다는 걸 알 수 있다. 실제로 확인해보면 다음과 같다.

System.identityHashCode()는 OS(System)에서 가지는 주소값을 보여준다. 두 객체는 서로 다른 주소값을 참조하고 있기 때문에 ex1 인스턴스의 값을 변경하더라도 독립적으로 값을 유지할 수 있었다.

관련 내용 참조 : https://datamod.tistory.com/57


이번엔 객체를 그대로 호출해서 사용해보았다. 아까 작성한 exam 클래스에서 static으로 선언한 변수를 호출해보겠다.

exam.class

1
2
3
4
public class exam {
public static String classVar = "class 변수";
public String instanceVar = "instance 변수";
}

main.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Main {
public static void main(String[] args) {
// 인스턴스 생성
exam ex1 = new exam();
exam ex2 = new exam();

System.out.println("ex.classVar : "+ex1.classVar);
System.out.println("ex.classVar : "+ex2.classVar);

ex1.classVar = " changed by class";
System.out.println("ex.classVar : "+ex1.classVar);
System.out.println("ex.classVar : "+ex2.classVar);
}
}
1
2
3
4
5
// 출력 결과
ex1.classVar : class 변수
ex2.classVar : class 변수
ex1.classVar : changed by class
ex2.classVar : changed by class

이번엔 다른 결과가 출력되었다. ex1.classVar의 값만 바꿨을 뿐인데, ex2의 값도 바뀐걸 알 수 있다. 왜 그럴까?

마찬가지로 이번에도 System.identityHashCode()를 사용하여 각각 인스턴스들이 어떤 주소값을 참조중인지 확인해보았다.

모든 인스턴스 값이 참조하고 있는 주소가 같은 주소를 참조하고 있는걸 확인할 수 있다. 따라서 하나 인스턴스만 바꾸더라도 모든 인스턴스에서 값이 변경되는걸 알 수 있다.


static 변수을 가져와서 사용하는것과 인스턴스를 사용하는 것의 차이는 다음 그림으로 설명할 수 있다.

인스턴스를 생성해서 사용하면 사용하면 인스턴스마다 새로운 주소값을 참조하게 되기 때문에 값을 변경(=주소값 변경)하더라도 다른 인스턴스에 영향을 주지 않는다.

반면 static 변수를 사용할 경우에는 같은 주소값을 서로 참조하고 있으므로 값이 바뀌면(주소값 변경), 당연히 사용하는 모든 인스턴스의 값도 변경되는 것이다.