퉁탕퉁탕 만들어보자

Java의 primitive type, reference type, wrapper class 본문

Computer/Java

Java의 primitive type, reference type, wrapper class

호숀티 2022. 4. 17. 14:44
반응형

 

java 의 타입은 크게 primitive type, reference type, null type 3가지가 있다.

 

primitive type이란 boolean, int, char와 같은 타입이다. 이 타입은 이름공간에 바로 값이 저장되기 때문에 stack에 저장된다. (array제외)

 

reference type은 class의 instance로 생성된 object들이 reference타입이다. 얘네들은 heap영역에 할당된다. reference type은 그 값을 참조하는 친구가 stack에 주소를 갖고있고, 실제 값은 heap에 할당된다.  따라서 == operator가 아닌 equals() 메소드로 비교를 해야한다.

// reference type
Person p = new Person();

// primitive type
int a = 3;
boolean b = false;

 

우리가 자주 사용하는 String이라는 친구!

그런데 String같은 경우에는 reference type인 것을 잘 까먹고 primitive 타입처럼 사용을 하게된다. 이제 값을 비교해보자.

String s1 = "Grape";
String s2 = "Grape";
String s3 = "Orange";
System.out.println(s1==s2); // true
System.out.println(s1.equals(s2)); // true
System.out.println(s1==s3); //false

String s4 = new String("Apple");
String s5 = new String("Apple");
System.out.println(s4==s5); // false
System.out.println(s4.equals(s5)); // true

오옷? String s1 = "---" 으로 생성한것과 new String("---") 으로 생성된것이 비교의 결과가 다르다. 왜일까?

 

우리가 익히 알아온바로는, String은 reference type이기 때문에 그래서 new String으로 객체를 생성하게되면, s4와 s5에는 주소값이 들어가게 되고, object는 각각 따로 생성되서 heap에 할당된다. 따라서 둘의 주소값이 달라서 s4와 s5를 비교했을 때 동일하지 않다고 나오고, equals로 비교하면 값을 비교하게 되니까 true가 나온다.

 

그러면 String s1 = "Grape"은 어디에 존재하는걸까? 바로 String constant pool을 알아야한다.

String constant pool이란, heap에 존재하는 별도의 공간으로 프로그램에서 사용되는 sonstant string값들이 저장되는 공간이다. 만약 String s1 = "Grape"으로 선언하고 그다음 String s2 = "Grape"로 동일하게 만들면, 이미 존재하는지 확인을 하고 -> 이미 있다면 s2는 s1이 가리키는 곳을 동일하게 가리켜서 재사용 할 수 있게 한다. String s3="Orange" 에서는  없기때문에 새로 할당한다. 이 과정을 intern()이라고 하고,  대략적으로 그림으로 나타내면 다음과 같다.

 

대신 이 친구들은 constant인 경우에만 활용되고 런타임에 할당되는 variable로 string을 만드는 경우에는 intern되지 않는다고 한다. GC는 heap이기 때문에 다른 heap에 존재하는 친구들과 동일하게 GC된다 (java 6 이하에서는 아니었다고함)

 

그래서 우리가 constant한 String을 사용을 할때는 String 객체를 사용해서 string constant pool 덕분에 메모리가 잘 활용된다.

 

그럼 String에 변경을 주면 어떻게 될까?

String a = "Orange";
a += " is";
a += " delicious";

String자료형은 immutable 이기 때문에, a주소의 "Orange"가 변경되는 것이 아니라, 새로운 메모리를 계속 할당하게 된다.

 

따라서 우리는 String값에 변경이 있을것으로 예상할때는 저렇게 사용하지 않고 StringBuilder를 사용한다.

StringBuilder strBuilder = new StringBuilder();

strBuilder.append("orange");
strBuilder.append("is");
strBuilder.append("delicious!);

strBuilder.toString();

 

StringBuilder의 구현은 실제로 배열에 새로운 CharSequence를 하나씩 넣어주게 되어있어서, 같은 주소를 활용할수있다.

@Override
public AbstractStringBuilder append(CharSequence s, int start, int end) {
    if (s == null)
        s = "null";
    if ((start < 0) || (start > end) || (end > s.length()))
        throw new IndexOutOfBoundsException(
            "start " + start + ", end " + end + ", s.length() "
            + s.length());
    int len = end - start;
    ensureCapacityInternal(count + len);
    for (int i = start, j = count; i < end; i++, j++)
        value[j] = s.charAt(i);
    count += len;
    return this;
}

그러면 StringBuffer는 언제 쓰는걸까!?

StringBuffer역시 StringBuilder와 비슷하지만 synchronized가 내부 함수에 전부 붙어있어서 스레드간 꼬이지 않도록 멀티스레드간 안전하게 활용할 수있다.

wrapper class 란 무엇일까?

바로 Integer, Boolean 같이 primitive type들을 object로 한겹 감싸주는 친구라고 볼수있다. (이걸 박싱, 언박싱이라고 한다).

왜 wrapper타입을 쓸까? 보통은 Collection을 Generic type으로 생성할때 primitive 타입을 사용할 수 없기 때문이다.

List<int> myPrimitiveNumbers //ㅇㅔ러 발생
List<Integer> myNumbers = new ArrayList<>(); //올바른사용

또는 리턴값으로 null 또는 자료형을 리턴하고싶을때 Integer num = null; 대입이 가능하기 때문에 쓸 때도 있다.

 

Primitive Data Type Wrapper Class

byte Byte
short Short
int Integer
long Long
float Float
double Double
boolean Boolean
char Character

Wrapper type 데이터들의 큰 특징은 null가능, reference value인 것과 더불어, immutable value라는 것이다. 즉 연산을 하게 되면 그 object의 값이 변경되는게 아니라 새로운 object instance가 생성된다.

 

아래 코드가 수행될때 modify 함수 안에서 어떤일이 일어나는지 살펴보자

public static void main(String[] args) {
	Integer i = new Integer(100);
	i = modify(i);
}

private Integer modify(Integer i) {
	return i = i + 1;
}
  • i를 언박싱해서 100을 꺼낸다.
  • 100에다가 1을 더해서 101을 만든다.
  • 새로운 Integer Object를 생성해서 101을 저장한다.
  • 새로 만든 Integer Object를 i에 할당한다. (i가 레퍼런스 하는 친구가 바뀜)
728x90
반응형

'Computer > Java' 카테고리의 다른 글

HashMap 충돌 (java 8)  (0) 2022.05.08
OutputStream  (0) 2022.05.07
InputStream  (0) 2022.05.07
Math class - Java  (0) 2022.04.03
String 함수들, 자료구조 - Java  (0) 2022.04.03