- String
자바에서 문자열은 변수 String에 저장한다. 특이점이 있다면 String은 다른 참조타입변수들과는 달리 저장된 문자열이 같으면 객체를 공유하게 되어 같은 객체를 참조하게 한다.
따라서 아래 코드를 실행시켜보면 "같은 객체 참조" 라는 출력문이 나올 것이다.
String name1 = "KSH";
String name2 = "KSH";
if(name1 == name2){
system.out.println("같은 객체 참조");
}else{
system.out.println("다른 객체 참조");
}
만일 같은 문자열이더라도 다른 객체를 참조하게 하고싶다면 객체 생성 연산자인 new를 사용하면 된다.
String name1 = new String("KSH");
String name2 = new String("KSH");
if(name1 == name2){
system.out.println("같은 객체 참조");
}else{
system.out.println("다른 객체 참조");
}
위 코드를 실행시켜보면 "다른 객체 참조" 라는 출력문이 나올 것이다.
만일 객체 일치/불일치에 상관없이 문자열만을 비교하고 싶다면 메소드 equals()를 기억하면 된다.
ex) boolean result = name1.equals(name2);
참조타입인 String은 초기값으로 null을 가질 수 있다. 마찬가지로 객체를 참조하다가 후에 null값으로 초기화되면 heap 영역에 생성되어 있던 객체는 가비지 콜렉터에 의해 제거된다.
- 배열
한번 선언하면 고정된 크기를 갖는 배열은 객체가 index를 값으로 갖게 한다.
예를 들어
int[] num = {1,2,3,4};
라는 배열을 생성하면 메모리는 다음과 같을 것이다.
배열을 생성함으로써 생기는 heap 영역에는 1, 2, 3, 4같이 저장된 값을 index로 갖는 객체가 생성된다. 각 index가 갖는 메모리 크기는 선언한 배열의 타입에 따라 다르며 이 경우에는 4byte이다. 따라서 배열 num이 차지하는 메모리의 총 양은 10번지로부터 16byte까지인 것이다. 그렇다면 메모리 범위가 넓기 때문에 참조를 어떻게 하는지 궁금할텐데, stack에서는 객체로부터 리턴된 index를 변수에 저장하는 것으로 참조한다.
기본 변수와는 달리, 참조 변수가 가지는 객체 때문에 매개변수 활용에서 에러가 날 수 있다.
예를 들어, 배열을 매개변수로 받는 two라는 함수가 있다고 가정하고, main에서 two 함수를 활용하려 할 때 ? 안에는 어떤 코드가 들어가야 컴파일에러가 나지 않을까?
public static int two(int[] arr){
System.out.println("index 2 = " + arr[2]);
return 0;
}
public static void main(String[] args){
int result = two( ? );
}
main 함수에 int[] num = {1,2,3,4); 와 같은 임의의 배열 num이 있다면 ( ? )에 배열 이름인 num이 들어가면 된다. 그러나 위 코드처럼 별도의 배열을 만들지 않았다면 ( ? )에 배열을 직접 넣어줘야한다. 그리고 새로운 배열을 생성하는 것이기 때문에 객체를 생성해줘야하므로 ( ? )에는 new int[] {1,2,3,4} 가 들어가야한다.
String과 마찬가지로 배열도 초기값으로 null을 가질 수 있다. null값을 가진다는 것은 stack에 변수만 저장되고 heap에는 객체가 생성되지 않는다는 것을 의미한다. 그렇기에 어떠한 이유로 배열에 저장할 값의 list를 알지 못하지만 객체는 생성하고 싶다면 null을 사용해서는 안된다. 이 경우에는 new 연산자를 사용하여 비어있는, 고정된 크기의 배열을 생성할 수 있다. 사용형태는 type[] 변수명 = new type[배열크기]; 가 되겠다.
ex) 길이가 5인 age라는 이름의 int형 배열
int[] age = new int[5];
이때 비어있는 배열에 저장되는 값들은 배열 타입의 초기값이다. byte, short, int는 0, String, 클래스, 인터페이스는 null, boolean은 false 가 초기값이다.
배열의 타입은 위에서 언급했듯이 다양한데, 그 중 String타입의 배열은 내부 데이터 또한 String이므로 혹여 값의 비교를 할 때 문자열 비교는 equals(), 객체 비교는 == 또는 != 사용해야함을 잊지 말도록 하자.
배열의 길이는 배열이름.length; 로 얻을 수 있는데, length는 read only field이기 때문에 = 연산자의 왼쪽에 올 수 없다.
배열을 복사하는 방법은 2가지가 있다. for문을 돌려서 배열의 값들을 하나하나 복사하는 방법, 하나는 메소드System .arraycopy() 를 사용하는 방법. 전자는 쉬우니까 넘어가고, System.arraycopy()에 대해 알아보자.
복사할 배열의 이름이 arr1, 복사한 값을 저장할 배열의 이름이 arr2라고 가정했을 때, 메소드 사용방법은 다음과 같다.
System.arraycopy(arr1, 0, arr2, 0, 5);
첫번째 인자는 복사할 배열, 두번째 인자는 복사를 시작할 index, 세번째 인자는 복사한 값을 저장할 배열, 네번째 인자는 값을 저장할 시작 index, 다섯번째 인자는 복사할 index의 개수이다.
이때 copy되는 것은 객체의 주소이기 때문에 참조되는 객체는 동일하다. 이러한 copy를 shallow copy라고 한다.
한걸음 더 나아가 이차원 배열에 대해 생각해보자.
이차원 배열의 형태는 수학에서의 행렬을 생각하면 된다. 차이점이 있다면 행렬과는 달리 이차원 배열은 계단식 구조를 가질 수도 있다는 점이다.
예를 들어,
int[][] table = { {1,2,3}, {4,5,6} };
라는 배열을 생성하면 메모리 영역이 어떤 형태를 가질까? 당연히 일반 배열과 마찬가지로 heap 영역에 생성되는 객체가 1개일거라고 생각했지만 오답이었다. 결론부터 말하자면 이차원배열에서 생성되는 객체의 개수는 배열의 행의 개수+1와 같다. 자세한 이해를 위해 그림을 그려보았다.
쉽게 생각하면 각 행을 기준으로 일차원 배열이 생성된다고 생각하면 된다. 또한 위 그림을 통해 이차원 배열의 길이는 행과 열의 길이 중 행이라는 것을 알 수 있을 것이다. 따라서 table.length의 결과는 2이다. 또한 객체 2, 3의 index의 길이는 table[0].length, table[1].length 로 구할 수 있다.
비어있는 고정된 크기의 이차원 배열을 만들어야 할 때도 있을 것이다. 이때도 new 연산자를 사용하면 된다.
예를 들어,
int[][] table = new int[2][3];
위 코드는 행이 2개, 열이 3개이고 0으로 초기화된 이차원배열을 생성한다.
위에서 행렬과 달리 이차원배열은 계단식 구조를 가질 수 있다고 했다. 아래 그림과 같은 배열을 만들려면 어떤 코드가 필요할까?
먼저 배열을 선언하고 객체를 선언해준다. 이때 기준이 되는 행만 고정크기를 정해두고 열은 비워둔다.
int[][] table = new int[4][];
이때 heap 영역에는 객체가 하나 생성된다. 그러면 추가로 생성되야 하는 객체가 4개임을 이제 우리는 안다. 다음과 같이 각 행에 맞춰 객체를 생성해주는데 이때 각 객체 내부의 배열의 크기는 1에서부터 4까지 1씩 증가할 것이다.
table[0] = new int[1];
table[1] = new int[2];
table[2] = new int[3];
table[3] = new int[4];
이 상태에서 값을 채워 넣는 방법은 table[0][0] = {1}; table[1][0] = {1}; 처럼 하나하나 저장하는 것이다.
또는 table[3] = new int[4] {1,2,3,4}; 처럼 객체를 생성함과 동시에 값을 넣어줄수도 있다.
- 열거
열거타입은 한정된 값만을 가지기 때문에 다른 참조타입변수들에 비하면 사용빈도가 적다고 생각한다. 그렇지만 종종 유용하게 사용될 수 있기 때문에 알아두면 좋다. 특이하게 열거타입은 새로운 java 파일을 만들어 선언을 해도 되고, 클래스 안 또는 밖에서 선언을 해줘도 된다. 개인적으로는 따로 파일을 만들어 사용한다.
선언 형태는 public enum 이름{ . . . } 이다.
봄, 여름, 가을, 겨울로 한정된 값만을 가지는 계절을 예제로 클래스를 생성해보았다. 열거타입의 이름은 Season이고, SPRING, SUMMER, AUTUMN, WINTER은 열거상수이다. 참고로 열거타입도 참조타입변수이므로 null을 저장할 수 있다.
enum class를 생성했으니 열거상수를 사용하기 위해 새로운 클래스를 만들어 예제코드를 만들어보았다. 현재 계절을 알 수 있게 해주는 코드이다.
public class Season2 {
public static void main(String[] args){
Season now;
Calendar cal = Calendar.getInstance();
int month = cal.get(Calendar.MONTH)+ 1;
if(month>=3 && month<=5){
now = Season.SPRING;
System.out.println("계절은 " + now);
}
else if(month>=6 && month<=8){
now = Season.SUMMER;
System.out.println("계절은 " + now);
}
else if(month>=9 && month<=11){
now = Season.AUTUMN;
System.out.println("계절은 " + now);
}
else{
now = Season.WINTER;
System.out.println("계절은 " + now);
}
}
}
열거 클래스에 저장된 열거 상수들을 가져다 쓰기 위해서는 일단 3행처럼 열거타입의 변수를 선언해줘야한다.
그리고 필요에 따라 열거타입변수 = 열거타입.열거상수; 처럼 변수에 값을 저장해 사용하면 된다.
열거타입을 사용할 때 메모리를 보면 이전의 참조타입변수들과 달리 stack, heap 뿐만이 아니라 method 영역도 같이 봐줘야 한다.
위 그림을 보면, 메소드 영역에는 열거상수들이 저장된다. 그리고 각 열거상수는 heap에 저장된 객체의 주소를 참조한다. 위 코드에서 선언된 열거타입변수 now는 stack에 저장이 되는데, now = Season.열거상수; 코드에 의해 now에는 열거상수가 참조하는 객체의 주소가 저장된다. 따라서 지금은 5월이니 ? 에는 100 번지가 저장될 것이다.
열거 상수의 String을 내부 data로 갖는 열거 객체가 가지고 있는 method에 대해 알아두면 여러모로 편리하다.
name()
열거객체 내부에 저장된 String을 리턴
리턴 타입: String
ex) Season now = now.SPRING;
String str = now.name();
ordinal()
열거객체의 순번을 리턴
리턴 타입: int
ex) Season now = now.SUMMER;
int index = now.ordinal();
compareTo()
매개값을 기준으로, 비교하는 열거객체의 순번이 빠르면 음수, 느리면 양수를 리턴
리턴 타입: int
ex) Season now1 = now.AUTUMN;
Season now 2 = now.WINTER;
int result = now1.compareTo(now2);
valueOf()
매개값으로 주어진 String을 열거객체로 변환하여 리턴
리턴 타입: 열거
ex) Season now = Season.valueOf("SUMMER");
values()
열거타입의 모든 열거객체를 배열로 만들어 리턴
리턴 타입: 열거형 배열
ex) Seaon[] arr = Season.values();
생성된 배열의 각 index에는 열거객체의 주소가 저장되어 있다.
index 순번은 열거객체의 순번과 동일
위 메소드들은 java.lang.Enum 클래스에 선언된 것들로, 모든 열거타입은 Enum class를 상속하기 때문에 아무 제재없이 사용 가능하다.
(이 글이 도움이 됐다면 광고 한번씩만 클릭 해주시면 감사드립니다, 더 좋은 정보글 작성하도록 노력하겠습니다 :) )
'간단 지식 > Java' 카테고리의 다른 글
알아두면 편한 메소드 (0) | 2020.05.26 |
---|---|
05. main 메소드의 매개값 - String[] args (0) | 2020.05.26 |
03. Java의 메모리 영역 간단정리 (0) | 2020.05.10 |
02. 기본 타입 변수와 참조 타입 변수 (0) | 2020.05.08 |
01. 자동타입변환과 강제타입변환 (0) | 2020.05.01 |