Written by
Poogle
on
on
자바 기초 - Type
자료형과 타입
- 값의 종류에 따라 저장될 공간의 크기와 저장 형식을 정의한 것
- 문자형(char), 정수형(byte, short, int, long), 실수형(float, double)
- 기본형은 저장할 값의 종류에 따라 구분되므로 기본형의 종류를 얘기할 때는 ‘자료형(data type)’
- 참조형은 ‘객체의 주소(4 byte 정수)’를 저장하므로 값(data)이 아닌 객체의 종류에 의해 구분되므로 타입(type)
- 타입에 자료형이 포함되므로 굳이 구분 안해도 된다
기본형과 참조형
기본형 Primitive
- 실제 값(data)을 저장
- 8가지
참조형
- 어떤 값이 저장되어 있는 주소(memory address)를 값으로 가짐
- 변수 선언 시 변수에 값이 저장되는 것이 아니라 객체에 대한 힙 영역의 참조를 저장
- 같은 참조를 가리키고 있으면 한 쪽에서 객체의 상태를 변경 -> 다른 쪽에서도 영향을 받음
- 기본형 8가지를 제외한 나머지
- null로 초기화
- null의 의미가 null 참조를 의미
Call by Value & Call by Reference
Call by Value(값에 의한 호출)
- 인자로 받은 값을 복사하여 처리
- 장: 복사하여 처리하기 때문에 안전, 원래의 값 보존
- 단: 복사 -> 메모리 사용량
public class Example {
public static void methodBefore() {
int a = 1;
int b = 2;
System.out.println("Before: " + "a = " + a + ", b = " + b);
methodAfter(a, b);
System.out.println("After: " + "a = " + a + ", b = " + b);
}
public static void methodAfter(int a, int b) {
a = 3;
b = 4;
}
public static void main(String[] args) {
methodBefore();
}
}
- 결과
Before: a = 1, b = 2 After: a = 1, b = 2
methodOne()
과methodTwo()
에서 사용하는 변수들은 이름만 같을 뿐 다른 주소를 가짐 -> 값을 수정해도 영향을 미치지 못함
Call by Reference(참조에 의한 호출)
- 인자로 받은 값의 주소를 참조하여 직접 값에 영향을 줌
- 장: 빠름
- 단: 직접 참조 -> 원래 값이 영향을 받음
public class Example {
public static void methodBefore() {
Person person = new Person(27, "Poogle");
System.out.println("Before: " + "age = " + person.age + ", name = " + person.name);
methodAfter(person);
System.out.println("After: " + "age = " + person.age + ", name = " + person.name);
}
public static void methodAfter(Person person) {
person.age = 29;
person.name = "Solar";
}
public static void main(String[] args) {
methodBefore();
}
}
class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
- 결과
Before: age = 27, name = Poogle After: age = 29, name = Solar
public class Example {
public static void methodBefore() {
Person person = new Person(27, "Poogle");
System.out.println("Before: " + "age = " + person.age + ", name = " + person.name);
methodAfter(person);
System.out.println("After: " + "age = " + person.age + ", name = " + person.name);
}
public static void methodAfter(Person person) {
person = new Person(29, "Solar");
}
public static void main(String[] args) {
methodBefore();
}
}
class Person {
int age;
String name;
public Person(int age, String name) {
this.age = age;
this.name = name;
}
}
- 결과
Before: age = 27, name = Poogle After: age = 27, name = Poogle
Constant Pool
String 객체를 생성하는 방법
Literal (“”)
- 내용이 같다면 같은 객체
@DisplayName("literal로 생성 시 동일") @Test void stringLiteral() { String str1 = "abcde"; String str2 = "abcde"; assertThat(str1).isEqualTo(str2); }
new 연산자 사용
- 내용이 같아도 개별적인 객체
@DisplayName("new로 생성한 String 객체는 값이 같아도 동일하지 않음") @Test void stringNew() { String str1 = new String("1234"); String str2 = new String("1234"); assertThat(str1).isNotSameAs(str2); }
intern()
메서드로 String Pool에 있으면 그 객체를 그대로 리턴, 그렇지 않으면 String Pool에 추가하고 객체의 reference를 리턴@DisplayName("String Pool 바깥에 있던 String 객체를 intern -> String Pool에 추가") @Test void internedString() { String constant = "interned String"; String newString = new String("interned String"); assertThat(constant).isNotSameAs(newString); String internedString = newString.intern(); assertThat(constant).isSameAs(internedString); }
String, StringBuffer, StringBuilder
String
- 불변
- 문자열 추가/수정/삭제 시 힙에 계속해서 생성됨 -> 힙 메모리 부족
- 멀티쓰레드 환경에서의 안전(thread-safe)
StringBuffer, StringBuilder
- 가변 -> 동일 객체 내에서 문자열 변경
- 동기화의 유무
StringBuffer
- 내부적으로 문자열 편집을 위한 버퍼를 가지고 있음. 인스턴스를 생성할 때 그 크기를 지정할 수 있음
- 동기화 지원 -> 멀티 쓰레드로 작성된 프로그램이 아닌 경우 동기화는 불필요하게 성능을 떨어뜨림
- 멀티 쓰레드 환경에서 안전(thread-safe)
- web이나 socket 같이 비동기로 동작하는 경우 안전
- StringBuffer는
equals()
를 오버라이딩 하지 않음 ->equals()
나==
가 같은 결과를 얻을 수 있음 toString()
은 오버라이딩 함
StringBuffer sb1 = new StringBuffer("abc");
StringBuffer sb2 = new StringBuffer("abc");
sb1 == sb2; //false
sb1.equals(sb2); //false
String s1 = sb1.toString();
String s2 = sb2.toString();
s1.equals(s2); //true
StringBuilder
- 동기화 지원 X (StringBuffer에서 쓰레드 동기화만 뺀 것)
- 단일 쓰레드에서 성능이 뛰어남