본문 바로가기
java

list, map

by wjdtmdgjs 2024. 7. 25.

얕은 복사
- 앞서 설명드린 것처럼 배열은 참조형 변수이며 실제 값이 아닌 실제 값의 주소값을 가진다
- 따라서 배열 변수 간에 대입 연산자 `=`를 사용해서 복사를 하게 되면 주소값만 복사됩니다.
// 얕은 복사

int[] a = { 1, 2, 3, 4 };
int[] b = a; // 얕은 복사

b[0] = 3; // b 배열의 0번째 순번값을 3으로 수정했습니다. (1 -> 3)

System.out.println(a[0]); // 출력 3  <- a 배열의 0번째 순번값도 3으로 조회됩니다. 

깊은 복사
- 얕은 복사처럼 가짜 복사가 아니라 진짜 새로운 배열을 똑같이 만들고 싶을 때 깊은 복사를 합니다.
- 깊은 복사는 결국 실제 값을 가지고 있는 배열의 기본형 값을 꺼내서 복사해 주면 됩니다.
- 반복문 `for 문` 을 통해서 하나씩 꺼내서 복사해 주는 방법과 여러 메서드를 사용하는 방법이 있습니다.
// 깊은 복사

int[] a = { 1, 2, 3, 4 };
int[] b = new int[a.length]; 

for (int i = 0; i < a.length; i++) {
    b[i] = a[i]; // 깊은 복사
}

b[0] = 3; // b 배열의 0번째 순번값을 3으로 수정했습니다. (1 -> 3)

System.out.println(a[0]); // 출력 1 <- 깊은 복사를 했기때문에 a 배열은 그대로 입니다.

깊은 복사 메서드
// 깊은 복사 메서드

// 1. clone() 메서드
int[] a = { 1, 2, 3, 4 };
int[] b = a.clone(); // 가장 간단한 방법입니다. 
// 하지만, clone() 메서드는 2차원이상 배열에서는 얕은 복사로 동작합니다!!

// 깊은 복사 메서드

import java.util.Arrays;

public class Main {
public static void main(String[] args) {
// 2. Arrays.copyOf() 메서드
int[] a = { 1, 2, 3, 4 };
int[] b = Arrays.copyOf(a, a.length); // 배열과 함께 length값도 같이 넣어줍니다.
}
}

문자(char/ 1byte), 문자열(String)
String = char[]

기본형 변수 vs 참조형변수
1.기본형 변수는 '소문자로 시작함' 반면, 참조형 변수는 '대문자로 시작함'
 -Wrapper class에서 기본형 변수를 감싸줄 때(boxing), int->Integer
2.기본형 변수는 값 자체를 저장, 참조형 변수는 별도의 공간에 값을 저장 후 그 주소를 저장함(=주소형변수)

char< String(훨씬 더 많이씀)
String이 가지고 있는 기능이 넘 ㅜ많아서.
Wrapper class와도 상당히 비슷. 기본형 변수가 가지고있는 기능이 제한-> 다양한 기능을 제공하는 wrapper을 감쌈으로서, 추가기능을 더함


- String 기능 활용하기

    // String 기능 활용하기
    
    String str = "ABCD";
    
    // length()
    int strLength = str.length();
    System.out.println(strLength);  // 4 출력
    
    // charAt(int index)
    char strChar = str.charAt(2); // 순번은 0부터 시작하니까 2순번은 3번째 문자를 가리킵니다.
    System.out.println(strChar);  // C 출력
    
    // substring(int from, int to)
    String strSub = str.substring(0, 3); // 0~2순번까지 자르기 합니다. (3순번은 제외)
    System.out.println(strSub);  // ABC 출력
    
    // equals(String str)
    String newStr = "ABCD";  // str 값과 같은 문자열 생성
    boolean strEqual = newStr.equals(str);
    System.out.println(strEqual); // true 출력
    
    // toCharArray()
    char[] strCharArray = str.toCharArray(); // String 을 char[] 로 변환
    
    // 반대로 char[] 를 String로 변환하는 방법
    char[] charArray = {'A', 'B', 'C'};
    String charArrayString = new String(charArray); // char[] 를 String 으로 변환
    ```

생성
2차원 배열을 생성할 때도 대괄호를 하나 더 추가하면 됩니다. 
int[][] array = new int[][];
초기화
2차원 배열을 초기화는 아래 2가지 방법이 있습니다.
중괄호를 사용해 선언과 동시에 초기화합니다.
// 중괄호를 사용해 초기화

int[][] array = {
{1, 2, 3},
{4, 5, 6}
};

선언/생성 이후 반복문을 통해 초기화를 합니다.
// 반복문을 통한 초기화

int[][] array = new int[2][3]; // 최초 선언

for (int i = 0; i < array.length; i++) {
    for (int j = 0; j < array[i].length; j++) {
        arr[i][j] = 0;  // i, j 는 위 노란색 네모박스 안에있는 숫자를 의미하며 인덱스 라고 부릅니다.
    }
}

2. 가변 배열
    - Java 프로그래밍에서는 2차원 배열을 생성할 때 열의 길이를 생략하여, 행마다 다른 길이의 배열을 요소로 저장할 수 있습니다.
    - 이렇게 행마다 다른 길이의 배열을 저장할 수 있는 배열을 가변 배열이라고 합니다.
// 가변 배열

// 선언 및 초기화
int[][] array = new int[3][];
// 배열 원소마다 각기다른 크기로 지정 가능합니다.
array[0] = new int[2];
array[1] = new int[4];
array[2] = new int[1];

// 중괄호 초기화할때도 원소배열들의 크기를 각기 다르게 생성 가능합니다.
int[][] array2 = {
    {10, 20},
    {10, 20, 30, 40},
    {10}

};

// 3차원 배열의 이해

// 중괄호 3개를 써서 3차원 배열 초기화를 할 수 있습니다.
int[][][] MultiArray = {{{1, 2}, {3, 4}}, {{5, 6}, {7, 8}}};

// 최대값 구하기

int[] arr = { 3, 2, 1, 5, 1 };

// 최대값 초기값 세팅
int max = arr[0];

// 최대값 구하기
for (int num : arr) {
    if (num > max) { // 반복문 돌면서 나(max)보다 값이 작으면 저장
        max = num;
    }
}

// 최대값 5 출력
System.out.println(max);

- 1. 컬렉션🧬  이해하기
    - Java에서 컬렉션🧬 은 배열보다 다수의 참조형 데이터를 더 쉽고 효과적으로 처리할 수 있는 기능을 많이 가지고 있습니다.
        - 컬렉션🧬 기능 : 크기 자동 조정/ 추가/ 수정/ 삭제/ 반복/ 순회/ 필터/ 포함 확인 등….
    - 컬렉션🧬 종류
        - `Collection`에는 `List`, `Set` , `Queue` , `Map` 이 있습니다.
        - `List` : 순서가 있는 데이터의 집합 (데이터 중복 허용) - 배열과 비슷
        - `Queue` : 빨대🥤처럼 한쪽에서 데이터를 넣고 반대쪽에서 데이터를 뺄 수 있는 집합
            - First In First Out : 먼저 들어간 순서대로 값을 조회할 수 있다.
        - `Set` : 순서가 없는 데이터의 집합 (데이터 중복 허용 안 함) - 순서 없고 중복 없는 배열
        - `Map` : 순서가 없는 (Key, Value) 쌍으로 이루어진 데이터의 집합 (Key값 중복 허용 안 함)

List
순서가 있는 데이터의 집합 -> Array(최초 길이를 알아야 함!)
처음에 길이를 몰라도 만들 수 있음 -> List
1. Array -> 정적배열
2. List(ArrayList) -> 동적배열(크기가 가변적으로 늘어난다)
  - 생성 시점에 작은 연속된 공간을 요청해서 참조형 변수들을 담아놓는다.
  - 값이 추가될 때 더 큰 공간이 필요하면 더 큰 공간을 받아서 저장하니깐. 상관없다.

- 기능
    - 선언 : `ArrayList<Integer> intList` 형태로 선언합니다.
    - 생성 : `new ArrayList<Integer>();` 형태로 생성합니다.
    - 초기화 : 사이즈를 지정하는 것이 없기 때문에 초기화가 필요 없습니다.
    - 값 추가 : `intList.add({추가할 값})` 형태로 값을 추가합니다.
    - 값 수정 : `intList.set({수정할 순번}, {수정할 값})` 형태로 값을 수정합니다.
    - 값 삭제 : `intList.remove({삭제할 순번})` 형태로 값을 삭제합니다.
    - 전체 출력 : `intList.toString()` 형태로 전체 값을 대괄호`[]`로 묶어서 출력합니다.
    - 전체 제거 : `intList.clear()` 형태로 전체 값을 삭제합니다.

// ArrayList 
// (사용하기 위해선 import java.util.ArrayList; 를 추가해야합니다.)
import java.util.ArrayList;

public class Main {

public static void main(String[] args) {
ArrayList<Integer> intList = new ArrayList<Integer>(); // 선언 및 생성

intList.add(1);
intList.add(2);
intList.add(3);

System.out.println(intList.get(0)); // 1 출력
System.out.println(intList.get(1)); // 2 출력
System.out.println(intList.get(2)); // 3 출력
System.out.println(intList.toString()); // [1,2,3] 출력

intList.set(1, 10); // 1번순번의 값을 10으로 수정합니다.
System.out.println(intList.get(1)); // 10 출력


intList.remove(1); // 1번순번의 값을 삭제합니다.
System.out.println(intList.toString()); // [1,3] 출력

intList.clear(); // 전체 값을 삭제합니다.
System.out.println(intList.toString()); // [] 출력
}
}


- 2. LinkedList
    

    📌 `LinkedList`는 메모리에 남는 공간을 요청해서 여기저기 나누어서 실제 값을 담아 놓고, 실제 값이 있는 주소값으로 목록을 구성하고 저장합니다.
        
    - 특징
        - 기본적인 기능은 `ArrayList` 와 동일하지만 `LinkedList`는 값을 나누어 담기 때문에 모든 값을 조회하는 속도가 느립니다. 대신에, 값을 중간에 추가하거나 삭제할 때는 속도가 빠릅니다.
        - 중간에 값을 추가하는 기능이 있습니다. (속도 빠름)

// LinkedList 
// (사용하기 위해선 import java.util.LinkedList; 를 추가해야합니다.)
import java.util.LinkedList;

public class Main {

public static void main(String[] args) {
LinkedList<Integer> linkedList = new LinkedList<>(); // 선언 및 생성

linkedList.add(1);
linkedList.add(2);
linkedList.add(3);

System.out.println(linkedList.get(0)); // 1 출력
System.out.println(linkedList.get(1)); // 2 출력
System.out.println(linkedList.get(2)); // 3 출력
System.out.println(linkedList.toString()); // [1,2,3] 출력 (속도 느림)

linkedList.add(2, 4); // 2번 순번에 4 값을 추가합니다.
System.out.println(linkedList); // [1,2,4,3] 출력

linkedList.set(1, 10); // 1번순번의 값을 10으로 수정합니다.
System.out.println(linkedList.get(1)); // 10 출력

linkedList.remove(1); // 1번순번의 값을 삭제합니다.
System.out.println(linkedList); // [1,4,3] 출력

linkedList.clear(); // 전체 값을 삭제합니다.
System.out.println(linkedList); // [] 출력
}
}


📌 `Stack` 은 값을 수직으로 쌓아놓고 넣었다가 빼서 조회하는 형식으로 데이터를 관리합니다.

이걸 **“나중에 들어간 것이 가장 먼저 나온다(Last-In-First-out)”** 성질을 가졌다고 표현하며, 주로 상자와 비유해서 설명합니다.


- 특징
    - 상자에 물건을 넣고 빼는 것처럼 밑에서 위로 쌓고, 꺼낼 때는 위에서부터 꺼내는 형식입니다.
    - 그렇기 때문에 넣는 기능(`push()`) 과 조회(`peek()`), 꺼내는(`pop()`) 기능만 존재합니다.
    - 이렇게 불편하게 쓰는 이유는 최근 저장된 데이터를 나열하고 싶거나 데이터의 중복 처리를 막고 싶을 때 사용합니다.

- 기능
    - 선언 : `Stack<Integer> intStack` 형태로 선언합니다.
    - 생성 : `new Stack<Integer>();` 형태로 생성합니다.
    - 추가 : `intStack.push({추가할 값})` 형태로 값을 추가합니다.
    - 조회 : `intStack.peek()` 형태로 맨 위값을 조회합니다.
    - 꺼내기 : `intStack.pop()` 형태로 맨 위값을 꺼냅니다. (꺼내고 나면 삭제됨)

intStack.isEmpty();  ----> 스텍이 비어있으면 true, 아니면 false


// Stack 
// (사용하기 위해선 import java.util.Stack; 를 추가해야합니다.)
import java.util.Stack;

public class Main {

public static void main(String[] args) {
Stack<Integer> intStack = new Stack<Integer>(); // 선언 및 생성

intStack.push(1);
intStack.push(2);
intStack.push(3);

while (!intStack.isEmpty()) { // 다 지워질때까지 출력
    System.out.println(intStack.pop()); // 3,2,1 출력
}

// 다시 추가
intStack.push(1);
intStack.push(2);
intStack.push(3);

// peek()
System.out.println(intStack.peek()); // 3 출력
System.out.println(intStack.size()); // 3 출력 (peek() 할때 삭제 안됬음)

// pop()
System.out.println(intStack.pop()); // 3 출력
System.out.println(intStack.size()); // 2 출력 (pop() 할때 삭제 됬음)

System.out.println(intStack.pop()); // 2 출력
System.out.println(intStack.size()); // 1 출력 (pop() 할때 삭제 됬음)

while (!intStack.isEmpty()) { // 다 지워질때까지 출력
    System.out.println(intStack.pop()); // 1 출력 (마지막 남은거 하나)
}
}
}

- . Queue🥤
    

    📌  `Queue`은 빨대🥤처럼 한쪽에서 데이터를 넣고 반대쪽에서 데이터를 뺄 수 있는 집합입니다.
    
    
    - 특징
        - First In First Out : 먼저 들어간 순서대로 값을 조회할 수 있다.
        - 그렇기 때문에 넣는 기능(`add()`),  조회(`peek()`), 꺼내는(`poll()`) 기능만 존재합니다.
        - `Queue`는 생성자가 없는 껍데기라서 바로 생성할 수는 없습니다. (껍데기 = 인터페이스)
        - 생성자가 존재하는 클래스인 `LinkedList`를 사용하여 `Queue`를 생성해서 받을 수 있습니다.
        
        // LinkedList 를 생성하면 Queue 기능을 할 수 있습니다. (Queue 가 부모/ LinkedList 가 자식이기 떄문)
        Queue<Integer> intQueue = new LinkedList<Integer>();
        
    - 기능
        - 선언 : `Queue<Integer> intQueue` 형태로 선언합니다.
        - 생성 : `new LinkedList<Integer>();` 형태로 생성합니다.
        - 추가 : `intQueue.add({추가할 값})` 형태로 값을 맨 위에 추가합니다.
        - 조회 : `intQueue.peek()` 형태로 맨 아래 값을 조회합니다.
        - 꺼내기 : `intQueue.poll()` 형태로 맨 아래 값을 꺼냅니다. (꺼내고 나면 삭제됨)

// Queue 
// (사용하기 위해선 java.util.LinkedList; 와 import java.util.Queue; 를 추가해야합니다.)
import java.util.LinkedList;
import java.util.Queue;

public class Main {

public static void main(String[] args) {
Queue<Integer> intQueue = new LinkedList<>(); // 선언 및 생성

intQueue.add(1);
intQueue.add(2);
intQueue.add(3);

while (!intQueue.isEmpty()) { // 다 지워질때까지 출력
System.out.println(intQueue.poll()); // 1,2,3 출력
}

// 다시 추가
intQueue.add(1);
intQueue.add(2);
intQueue.add(3);

// peek()
System.out.println(intQueue.peek()); // 1 출력 (맨먼저 들어간값이 1 이라서)
System.out.println(intQueue.size()); // 3 출력 (peek() 할때 삭제 안됬음)

// poll()
System.out.println(intQueue.poll()); // 1 출력
System.out.println(intQueue.size()); // 2 출력 (poll() 할때 삭제 됬음)

System.out.println(intQueue.poll()); // 2 출력
System.out.println(intQueue.size()); // 1 출력 (poll() 할때 삭제 됬음)

while (!intQueue.isEmpty()) { // 다 지워질때까지 출력
System.out.println(intQueue.poll()); // 3 출력 (마지막 남은거 하나)
}
}
}

- 4. Set📚
    
    📌 `Set` 은 순서가 없는 데이터의 집합 (데이터 중복 허용 안 함) - 순서 없고 중복 없는 배열
    
    - 특징
        - 순서가 보장되지 않는 대신 중복을 허용하지 않도록 유지할 수 있습니다.
        - `Set`은 그냥 `Set`으로 쓸 수도 있지만 `HashSet`, `TreeSet` 등으로 응용하여 사용할 수 있습니다.
        - `Set`는 생성자가 없는 껍데기라서 바로 생성할 수는 없습니다. (껍데기 = 인터페이스)
        - 생성자가 존재하는 클래스인 `HashSet`를 사용하여 `Set`를 생성해서 받을 수 있습니다.
    - 기능
        - 선언 : `Set<Integer> intSet` 형태로 선언합니다.
        - 생성 : `new HashSet<Integer>();` 형태로 생성합니다.
        - 추가 : `intSet.add({추가할 값})` 형태로 값을 맨 위에 추가합니다.
        - 삭제 : `intSet.remove({삭제할 값})` 형태로 삭제할 값을 직접 지정합니다.
        - 포함 확인 : `intSet.contains({포함 확인 할 값})` 형태로 해당 값이 포함되어있는지 boolean 값으로 응답받습니다.


🔎 `HashSet` 외에도 `TreeSet`, `LinkedHashSet` 이 있습니다.

- `HashSet` : 가장 빠르며 순서를 전혀 예측할 수 없음
- `TreeSet` : 정렬된 순서대로 보관하며 정렬 방법을 지정할 수 있음
- `LinkedHashSet` : 추가된 순서, 또는 가장 최근에 접근한 순서대로 접근 가능

즉, 보통 `HashSet` 을 쓰는데 순서 보장이 필요하면 `LinkedHashSet` 을 주로 사용합니다

// Set 
// (사용하기 위해선 import java.util.Set; 와 java.util.HashSet; 를 추가해야합니다.)
import java.util.HashSet;
import java.util.Set;

public class Main {

public static void main(String[] args) {
Set<Integer> intSet = new HashSet<Integer>(); // 선언 및 생성

intSet.add(1);
intSet.add(2);
intSet.add(3);
intSet.add(3); // 중복된 값은 덮어씁니다.
intSet.add(3); // 중복된 값은 덮어씁니다.

for (Integer value : intSet) {
System.out.println(value); // 1,2,3 출력
}

// contains()
System.out.println(intSet.contains(2)); // true 출력
System.out.println(intSet.contains(4)); // false 출력

// remove()
intSet.remove(3); // 3 삭제

for (Integer value : intSet) {
System.out.println(value); // 1,2 출력
}
}
}

1. Map
    
    📌 여태까지 value 값들만 넣어서 관리하는 분류통(자료구조)를 배웠다면 Map 은 key-value 구조로 구성된 데이터를 저장할 수 있습니다.
    
    
    - 특징
        - key-value 형태로 데이터를 저장하기 때문에 기존에 순번으로만 조회하던 방식에서, key 값을 기준으로 vlaue를 조회할 수 있습니다.
        - key 값 단위로 중복을 허용하지 않는 기능을 가지고 있습니다.
        - `Map` 은 그냥 `Map`으로 쓸 수도 있지만 `HashMap`, `TreeMap`등으로 응용하여 사용할 수 있습니다.
        - `Map`으로 쓸 수도 있지만 `HashSet`, `TreeSet` 등으로 응용하여 사용할 수 있습니다.
    - 기능
        - 선언 : `Map<String, Integer> intMap` 형태로 Key타입과 Value타입을 지정해서 선언합니다.
        - 생성 : `new` `HashMap<>();` 형태로 생성합니다.
        - 추가 : `intMap.put({추가할 Key값},{추가할 Value값})` 형태로 Key에 Value값을 추가합니다.
        - 조회 : `intMap.get({조회할 Key값})` 형태로 Key에 있는 Value값을 조회합니다.
        - 전체 key 조회 : `intMap.keySet()` 형태로 전체 key 값들을 조회합니다.
        - 전체 value 조회 : `intMap.values()` 형태로 전체 value 값들을 조회합니다.
        - 삭제 : `intMap.remove({삭제할 Key값})` 형태로 Key에 있는 Value값을 삭제합니다.

// Map 
// (사용하기 위해선 import java.util.Map; 를 추가해야합니다.)
import java.util.Map;

public class Main {

public static void main(String[] args) {
Map<String, Integer> intMap = new HashMap<>(); // 선언 및 생성

//          키 , 값
intMap.put("일", 11);
intMap.put("이", 12);
intMap.put("삼", 13);
intMap.put("삼", 14); // 중복 Key값은 덮어씁니다.
intMap.put("삼", 15); // 중복 Key값은 덮어씁니다.

// key 값 전체 출력
for (String key : intMap.keySet()) {
System.out.println(key); // 일,이,삼 출력
}

// value 값 전체 출력
for (Integer key : intMap.values()) {
System.out.println(key); // 11,12,15 출력
}

// get()
System.out.println(intMap.get("삼")); // 15 출력
}
}

'java' 카테고리의 다른 글

getter&setter  (0) 2024.07.29
객체지향  (0) 2024.07.26
연산자, 조건문 (Sql 조금)  (1) 2024.07.24
JVM 공통 실행 환경  (6) 2024.07.22
package  (0) 2024.07.18