본문 바로가기
JAVA

변수, 기본형, 참조형 선언 with 메모리

by 고유빙글 2022. 12. 26.

변수타입

 

 : 기본형, 참조형

 

 

 

선언방식

 

 : 기본형 : 타입 변수명; 혹은 초기화를 같이 해주며 선언. ( 리터럴 방식 )

 

   참조형 : new로 선언. ( 생성자 방식 )

 

추가

 

 : String은 참조형 타입이지만 기본형처럼 사용할 수 있는 특수한 클래스.

 

 

 

 

기본 개요.

 

 : 기본형은 값을 갖는 타입. ( 메모리영역 stack에 해당 )

 

선언시 기본값이 있기에 값으로 null을 가질 수 없음. ( wrapper 클래스로 객체처럼 사용하여 null을 줄 수 있음 )

 

 

 

 : 참조형은 주소를 갖는 타입. ( 메모리영역 heap에 해당 )

 

null을 가질 수 있음.

 

 

 

 : String은 방식에 따라 기본형처럼도 참조형처럼도 사용할 수 있다.

 

리터럴 방식으로 선언해 기본형처럼 사용할 수도 ( 메모리영역의 method영역의 String Constant Pool )

 

생성자 방식으로 선언해 참조형처럼 사용할 수도 있다. ( 메모리영역 heap에 해당 )

 

 

 

기본 개요로 인한 특성

 

 : 기본형은 해당 변수에 접근하면 값을 바로 알 수 있기에 속도가 좀 더 빠름.

 

 : 기본형은 해당 변수에 접근하면 값을 바로 알 수 있어 == 연산자로 비교시 실제 값의 비교를 할 수 있음.

 

 

 

 : 참조형은 해당 변수에 접근하면 값을 갖고있는 classname@주소의 해쉬코드 를 알 수 있기 때문에 == 연산자로 비교시

 

  값의 비교를 할 수 없음.

 

 : 단, 참조형이더라도 toString()을 만들었다면 String Value로 접근할 수 있음.

ex )

public class Msg{

String m1 = "456";

String m2 = "789";

public String toString(){

return "Msg{m1 : "+m1+", m2 : "+m2+"}";

}

}

 

String a = "123";

Msg m = new Msg(); 

 

System.out.println(m);

a += m;

System.out.println(a);

 

out :Msg{m1 : 456, m2 : 789}

123Msg{m1 : 456, m2 : 789}

 

 

선언과 비교의 예시

 

 :      String a = "hello";

 

        String b = "hello";

 

        String c = new String("hello");

 

        System.out.println( a==b );

 

        System.out.println( b==c );

 

 

 

 의 코드를 보자.

 

 a,b은 리터럴 방식으로 선언. c는 생성자 방식으로 선언하였다. 이 경우 a == b는 String Constant Pool을 참조하기때문에

 

값처럼 true를 출력할 것이고

 

 b == c 는 c가 새로운 주소를 선언했기때문에 두 객체의 주소값이 다르므로 false를 출력할 것이다.

 

 

 

String은 값이 같더라도 주소가 다를 수 있어 .equals() 혹은 .compareTo() 메소드로 비교해야 한다.

 

객체의 비교는 .equals()와 .hashCode() 두 메소드를 오버라이드( 재정의 )해야한다.

 

 

 

equals는 비교하려는 방식을 정해줘야함에 따른 것이고,

 

hashCode는 비교의 기준이되는 주소값을 가져오는 방식을 정해줘야 함인데,

 

 

 

이는 hashTable등 자료구조를 좀 더 알면 보기 좋다.

 

 

 

 

 

new를 좀 더 알아보자

 

 : new 예약어는 memory allocation, memory distribution, memory clear의 기능을 한다.

 

메모리 정렬, 공간확보, 값 초기화 를 포함하는 명령어라고 보면 되고 주소값을 가져와 생성자를 실행시킨다.

 

 

 

c에서는 자동으로 해주지않아 메모리관리가 필요한데 자바는 메모리를 사용자가 고려할 일이 적다.

 

 

 

 

 

그렇다면 리터럴 방식과 new 방식은 ( 생성자 방식 ) 왜 다르게 하는가?

 

 : 기본형을 선언하는 리터럴 방식을 메모리의 크기 변화가 없다.

 

String마저도 그렇다. 이는 뒤에서 좀 더 자세히 적겠다.

 

 

 

기본형은 메모리 크기가 완전히 고정된 ( static ) 공간을 차지하도록 설계되어있어 별도의 과정없이 선언할 수 있다.

 

참조형은 메모리 크기가 제각각이기 때문에 new연산자로 class내부에 구성된 모든 변수들이

 

어느정도 static한 공간을 가질 수 있을지, 얼마나 차지할 수 있을지 미리 공간을 조성하는 부분을 포함한다.

 

 

 

 

 

String은 + 연산도 되는데 왜 메모리 크기변화가 없는가?

 

 : String은 불변객체다. 이름그대로 변하지 않는데 예를들어

 

 String a = "abc";

 

 a += "def";

 

 

 

 라고 한다면 a에는 "abc" 의 값을 가진 변수였다가

 

 "abcdef"의 값을 가진 변수가 되는거지, def가 뒤에 붙는것은 아니다. 즉, 새로운 값이 할당되기 때문에

 

이전의 값의 메모리 변화는 오지 않는다.

 

 

 그래서 사실 메모리, 연산의 낭비가 있어 이러한 경우에는 String보다 StringBuffer의 사용을 권장한다.

 물론 상황에 따른 장단이 있다. 이는 다른 포스트에서 다루겠다.