이전까지는 1열로 구성된 1차원 배열이었다면, 2차원 배열은 1차원 배열이 여러 개 존재하는 배열이라 볼 수 있다.
2차원 배열의 선언, 생성은 1차원 배열의 선언, 생성 방식에서 [ ]를 하나 더 추가하는 것이다.
// 선언 방식은 int[][] array, int array[][], int[] array[] 이다.
int[][] array;
int[][] array = new int[3][2];
2차원 배열의 조회 방식은 2중 반복문을 사용하여 조회할 수 있다.
// 조회
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j])
}
}
Java에서는 2차 배열을 생성할 때 배열의 크기를 생략할 수 있다.
즉, 원하는 크기만큼 각기 다른 크기로 배열을 설정할 수 있다는 의미이다.
3, 4, … 등 여러 다차원 배열이 있지만 일반적으로 3차원까지만 사용하는 경우가 많다.
다차원 배열이라 해서 1, 2차원 배열과 별반 다르지는 않다. 선언과 생성 방식도 동일하다.
// 3차원 배열 구조
int[][][] 3dArray = {{{1, 2}, {3, 4}, {5, 6}}, {{7, 8}, {9, 10}, {11, 12}}};
2차원 배열 조회할 때는 2차원 인덱스를 가진만큼 2중 반복문을 통해 출력했다.
이를 통해 가변 배열 역시 조회가 가능하다.
Int[][] array = {
{1, 2, 3},
{4, 5, 6, 7},
{8, 9}
}
for (int i = 0; i < array.length; i++) {
for (int j = 0; j < array[i].length; j++) {
System.out.println(array[i][j]); // 2중 반복문으로 i, j 인덱스 순회
}
}
Java에서 Collection은 배열보다 다수의 참조형 데이터를 더 쉽고 효과적으로 처리할 수 있는 표현이다.
크기 자동조정, 추가, 수정, 삭제, 반복, 순회, 필터, 포함 확인 등 다양한 기능들도 제공해주고 있다.
List: 순서가 있는 데이터들의 집합으로 배열과 비슷하며, 데이터 중복을 허용한다.
Queue: 한쪽에서 데이터를 넣고 반대쪽에서 데이터를 뺄 수 있는 집합, FIFO 구조이다.
Set: 순서가 없는 데이터의 집합이지만 중복은 허용되지 않는다.
Map: 순서가 없는 Key, Value 쌍으로 이루어진 데이터의 집합이다.
(Key값 중복 불가)
순서가 있는 데이터 집합으로, 길이를 지정하지 않아도 데이터를 저장할 수 있다.
즉, 동적 배열로 더 큰 길이가 요청될 때 더 큰 공간을 받아서 저장한다.
Import java.util.ArrayList;
ArrayList<Integer> intList = new ArrayList<Integer>();
intList.add(10); // 데이터를 리스트에 추가
intList.add(20);
intList.add(30);
System.out.println(intList.get(2)); // 2번에 위치한 30을 출력함
System.out.println(intList.toString); // 데이터를 문자열로 출력함
intList.set(0, 40); // 0번에 40이라는 데이터를 저장함, 기존 데이터를 덮어쓰기 당함
intList.remove(0); // 0번에 위치한 데이터를 제거함, 리스트의 길이가 줄어들고 0번에 기존 1번이 위치함
intList.clear(); // 리스트를 초기화함
⭐ LinkedList와 UnlinkedList의 차이
LinkedList는 메모리에 남는 공간을 요청해서 여기저기 나누어서 실제 값을 담는다.
실제 값이 있는 주소 값으로 목록을 구성하고 저장하는 자료구조이다.
하지만 LinkedList는 값을 나누어서 저장해두기 때문에 조회속도가 느리다. (추가, 삭제는 빠름)
LinkedList<Integer> linkedList = new LinkedList<Integer>();
linkedList.add(1, 1); // 데이터 1을 리스트의 1번에 추가, 0번은 빈 상태로 생성
linkedList.add(3); // 2번으로 데이터가 추가됨
System.out.println(linkedList.get(0)); // 0번 데이터 출력
System.out.println(linkedList.toString()); // 전체를 문자열로 출력, ArrayList보다 속도가 느림..
Stack은 수직으로 쌓은 Basket을 생각하면 이해가 편하다.
위로만 값을 저장할 수 있고 꺼낼 때는 위에서부터 꺼내는 구조이다. (FILO 구조)
왜 쓰냐? 최근 저장된 데이터가 필요한 상황에서 주로 사용된다.
Stack<Integer> intStack = new Stack<Integer>();
intStack.push(10); // 데이터를 Stack 안에 저장
intStack.push(20);
intStack.push(30);
System.out.println(intStack.peek()); // 저장된 데이터를 보여줌, 삭제는 없음
System.out.println(intStack.size()) // Stack의 크기를 보여줌, 즉 Stack에 데이터가 몇 개가 저장되어 있는지 알려줌
while(intStack.isEmpty) { // Stack 내부의 데이터가 없을 때까지
System.out.println(intStack.pop()); // pop은 데이터를 꺼내며 해당 데이터를 삭제한다.
}
Queue는 Stack과는 다르게 양방향 구조이다. 그래서 처음 넣은 순서대로 꺼낼 때도 빠져나가는 구조이다.
사용되는 메서드는 add, peek, poll로 구성되어 있다. 사용 방법은 Stack과 비슷하다.
하지만 Queue는 생성자가 없는 인터페이스로 다른 구조들과 다르게 new로 생성할 수 없다.
Queue<Integer> intQueue = new LinkedList<>();
intQueue.add(1);
intQueue.add(2);
intQueue.add(3);
System.out.println(intQueue.peek()); // 처음으로 저장된 값부터 출력
System.out.println(intQueue.size());
while(intQueue.isEmpty) {
System.out.println(intQueue.poll()); // FIFO에 맞춰 데이터를 꺼냄
}
Set은 집합과 같은 형태로, 순서 없이 데이터를 저장할 수 있다. 다만, 중복된 데이터도 없다.
Set도 Queue와 마찬가지로 생성자가 없기에, 바로 생성할 수 없다.
Set<Integer> intSet = new HashSet<>();
intSet.add(1);
intSet.add(12);
intSet.add(25);
for (Integer value: intSet) {
System.out.println(value);
}
System.out.println(intSet.contains(2)); // 데이터 2를 포함하고 있는지 확인, false 출력
Map은 Key-Value Pair 구조로, Key라른 값으로 Value가 특별하게 보장된다.
Map 역시 생성자가 없기에 Hashmap으로 구현할 수 있다.
Map<String, Integer> intMap = new HashMap<>();
IntMap.put(“첫번째”, 11);
IntMap.put(“두번째”, 22);
IntMap.put(“세번째”, 33);
IntMap.put(“네번째”, 44);
for (String key: intMap.keySet()) {
System.out.println(key); // key값 전체 출력
}
for (Integer value: intMap.values()) {
System.out.println(value); // value값 전체 출력
}
System.out.println(intMap.get(“세번째”)); // “세번째”라는 key를 가진 value 출력, 33출력