새소식

Java

[Java] List 리스트의 개념과 종류

  • -

 

 

리스트 List

 

1)   리스트의 개념

 

순서가 있는 데이터의 모음입니다.

 

 

 

 

 

 

 

 

 

2)   리스트의 종류

 

 

① ArrayList

 

● 개념

List 인터페이스를 구현한 클래스 중 크기가 동적으로 조정될 수 있는 가변 크기 배열

 

 

● 생성

List<타입> arrayList = new ArrayList<>();

 

*초기값을 가지는 배열 선언
List<String> myList = new ArrayList<>(Arrays.asList("apple", "banana", "orange"));

 

 

내부적으로 배열을 사용하여 요소를 저장합니다.

요소는 연속된 메모리 위치에 저장되며, 인덱스를 사용하여 접근할 수 있습니다.

 

 

 

● 특징

1) 자동크기조정

ArrayList는 요소의 추가나 삭제 시에 자동으로 크기를 조정합니다

기본적으로 요소가 추가될 때 배열의 크기는 현재 크기의 50% 증가량으로 조정되며, 요소가 삭제될 때 크기의 25% 감소량으로 조정됩니다.

 

요소의 추가와 삭제 시에는 배열의 재할당과 요소의 이동이 필요하므로 성능이 저하될 수 있습니다.

특히 중간에 요소를 삽입하거나 삭제하는 경우에는 뒤따르는 요소들의 이동이 필요하므로 성능이 저하될 수 있습니다.
 

 

2) 인덱스 기반 접근

ArrayList는 인덱스를 사용하여 요소에 접근할 수 있습니다. 인덱스는 0부터 시작하며, 요소의 순서를 나타냅니다.

 

 

3) 중복 허용

ArrayList는 중복된 요소를 허용합니다. 동일한 객체나 값의 여러 인스턴스를 저장할 수 있습니다.

 

 

 

● 예시

import java.util.ArrayList;
import java.util.List;

public class ArrayListExample {
    public static void main(String[] args) {
        List<String> pokemonList = new ArrayList<>();

        pokemonList.add("피카츄");
        pokemonList.add("꼬부기");
        pokemonList.add("파이리");

        System.out.println("포켓몬 리스트:");
        for (String pokemon : pokemonList) {
            System.out.println(pokemon);
        }
    }
}

출력 결과값
포켓몬 리스트:
피카츄
꼬부기
파이리

 

 

 

 

 

 

 

 

 

 

② LinkedList

 

● 개념

List 인터페이스를 구현한 클래스 중 각 요소가 자신의 이전 요소와 다음 요소에 대한 링크를 가지고 있는 이중연결리스트

 

 

 

● 생성

List<String> linkedList = new LinkedList<>();

 

 

 

● 특징

1) 이중연결리스트
자신의 이전 요소와 다음 요소에 대한 링크를 가지고 있어 순방향과 역방향으로 요소에 접근할 수 있습니다.
요소의 삽입과 삭제는 링크의 조절로만 이루어집니다.

 

 

2) 요소 접근

인덱스를 사용하여 요소에 접근할 수 있습니다.

선형적인 탐색을 수반하므로 ArrayList와 같은 인덱스 기반의 접근보다 느릴 수 있습니다.

 

 

3) 삽입과 삭제

삽입 또는 삭제할 요소의 앞 뒤 링크만을 조정하면 되기 때문에 요소의 이동이 발생하지 않아 빠르게 이루어집니다.

 

 

4) 크기 조정

요소의 추가나 삭제 시에 크기를 조정할 필요가 없습니다. 각 요소는 링크로 연결되어 있으며, 요소의 개수를 유연하게 조정할 수 있습니다.

 

 

 

● 예시

import java.util.LinkedList;
import java.util.List;

public class LinkedListExample {
    public static void main(String[] args) {
        List<String> pokemonList = new LinkedList<>();

        pokemonList.add("피카츄");
        pokemonList.add("꼬부기");
        pokemonList.add("파이리");

        System.out.println("포켓몬 리스트:");
        for (String pokemon : pokemonList) {
            System.out.println(pokemon);
        }
    }
}

출력 결과값
포켓몬 리스트:
피카츄
꼬부기
파이리

 

 

 

 

 

 

 

 

 

 

③  Vector

 

● 개념

Vector는 ArrayList와 유사한 기능을 제공하지만, 멀티스레드 환경에서 안전하게 사용할 수 있도록 설계되어있고,

동기화된 메소드로 구성되어 있습니다.

 

 

● 생성

List<String> vector = new Vector<>();

 

 

● 특징

1) 내부 배열
Vector는 내부적으로 배열을 사용하여 요소를 저장합니다.

 

 

2) 동기화된 메소드

Vector는 동기화된 메소드로 구성되어 있습니다.

멀티스레드 환경에서 여러 스레드가 동시에 Vector를 수정하더라도 안전하게 사용할 수 있습니다.

스레드 간의 동시 접근을 제어하고, 데이터 일관성을 보장 → 안전한 자료구조

 

 

3) 인덱스 기반 접근

Vector는 인덱스를 사용하여 요소에 접근할 수 있습니다. 인덱스는 0부터 시작하며, 요소의 순서를 나타냅니다.

 

 

4) 크기 조정

Vector는 요소의 추가나 삭제 시에 내부 배열의 크기를 동적으로 조정합니다.

요소의 개수에 따라 배열의 크기가 자동으로 조절되므로 크기를 직접 관리할 필요가 없습니다.

 

● 예시

import java.util.List;
import java.util.Vector;

public class VectorExample {
    public static void main(String[] args) {
        List<String> pokemonList = new Vector<>();

        pokemonList.add("피카츄");
        pokemonList.add("꼬부기");
        pokemonList.add("파이리");

        System.out.println("포켓몬 리스트:");
        for (String pokemon : pokemonList) {
            System.out.println(pokemon);
        }
    }
}


출력 결과값
포켓몬 리스트:
피카츄
꼬부기
파이리

 

 

 

 

 

 

 

 

 

 

 

 

④  Stack

 

● 개념

LIFO(Last-In, First-Out) 원칙을 따르는 자료구조

Stack은 요소의 추가와 제거가 스택의 맨 위에서만 이루어지는 자료구조라는 것이 특징!

 

 

● 생성

Stack<String> stack = new Stack<>();

 

 

● 특징

1) LIFO 원칙
Stack은 LIFO(Last-In, First-Out) 원칙을 따릅니다.
마지막에 추가된 요소가 가장 먼저 제거되고, 처음에 추가된 요소는 가장 마지막에 제거됩니다.

 

2) 주요 메소드

▶push(): 스택의 맨 위에 요소를 추가
▶pop(): 스택의 맨 위에서 요소를 제거하고 반환
▶peek(): 스택의 맨 위에 있는 요소를 반환하되, 제거하지는 않습니다. (스택의 상태를 확인하는 용도)
▶isEmpty(): 스택이 비어있는지 확인합니다. 비어있으면 true를 반환하고, 요소가 있으면 false를 반환합니다.
▶size(): 스택에 저장된 요소의 개수를 반환합니다.

 

 

3) 내부 구현

내부적으로 배열이나 LinkedList와 같은 자료구조를 사용하여 요소를 저장할 수 있습니다.

 

 

● 예시

import java.util.List;
import java.util.Stack;

public class StackExample {
    public static void main(String[] args) {
        Stack<String> pokemonStack = new Stack<>();

        pokemonStack.push("피카츄");
        pokemonStack.push("꼬부기");
        pokemonStack.push("파이리");

        System.out.println("스택에서 꺼낸 포켓몬:");
        while (!pokemonStack.isEmpty()) {
            String pokemon = pokemonStack.pop();
            System.out.println(pokemon);
        }
    }
}


★ 출력 결과값
스택에서 꺼낸 포켓몬:
파이리
꼬부기
피카츄

★ Stack 출력 결과값은 다른 것들과 상이하니, 꼭 확인할 것

 

 

 

 

 

 

 

 

 

 

 

 

⑤  CopyOnWriteArrayList

 

● 개념

수정 작업이 발생할 때 원본 리스트의 복사본을 만들어 작업을 수행하므로, 원본 리스트는 변경되지 않아, 안전한 자료구조

 

 

● 생성

List<String> copyOnWriteArrayList = new CopyOnWriteArrayList<>();

 

● 특징

1) 동기화
내부적으로 지원하는 동기화 처리로 인해 여러 스레드가 동시에 읽기 작업을 수행하더라도 상호간섭 없이 안정적인 동작을 보장

 

2) 복사본 생성

수정 작업이 발생하면 복사본을 생성하고, 해당 복사본에서 수정 작업을 수행합니다.

이를 통해 동시 수정 작업으로 인한 데이터 일관성 문제를 회피할 수 있습니다.

→ 단, 복사본의 생성으로 인해 성능 저하를 유발할 수 있음

 

 

3) 데이터 일관성

읽기 작업에 대한 데이터 일관성을 보장합니다.

읽기 작업 중에 다른 스레드에서의 수정 작업이 발생하더라도 원본 리스트는 변경되지 않으므로 읽는 동안 데이터 일관성을 유지할 수 있습니다.

 

 

● 예시

import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListExample {
    public static void main(String[] args) {
        List<String> pokemonList = new CopyOnWriteArrayList<>();

        pokemonList.add("피카츄");
        pokemonList.add("꼬부기");
        pokemonList.add("파이리");

        System.out.println("포켓몬 리스트:");
        for (String pokemon : pokemonList) {
            System.out.println(pokemon);
        }
    }
}


출력 결과값
포켓몬 리스트:
피카츄
꼬부기
파이리

 

 

 

 

 

 

 

 

⑥  List 종류별 요약표


종류 설명
ArrayList 가변 크기 배열로, 요소들을 인덱스 기반으로 저장하고 접근할 수 있습니다.
요소의 삽입과 삭제는 배열의 재할당이 필요할 수 있습니다.
LinkedList 이중 연결 리스트로, 각 요소는 자신의 이전 요소와 다음 요소에 대한 링크를 가지고 있습니다.
요소의 삽입과 삭제는 링크의 조정만으로 이루어집니다.
LinkedList
(Java 8
이상)
Java 8부터 LinkedList에는 추가적으로 메서드가 제공되어 사용이 용이해졌습니다.
예를 들어, 요소의 앞 뒤에 다른 요소를 삽입하는 메서드인 addFirst(), addLast()가 추가되었습니다.
Vector ArrayList와 유사하지만 동기화된 메서드로 구성되어 있어 멀티스레드 환경에서 안전하게 사용할 수 있습니다.
Stack LIFO (Last-In, First-Out) 원칙을 따르는 스택 자료구조입니다.
요소의 추가는 push() 메서드를 사용하고, 제거는 pop() 메서드를 사용합니다.
CopyOnWrite
ArrayList
멀티스레드 환경에서 안전한 리스트로,
수정 작업 시에는 복사본을 만들어 작업을 수행하므로 원본 리스트는 변경되지 않습니다.

 

 

 

 

 

 

 

 

 

3)   List 중간에 요소를 삽입/제거 하는 방법

 

 

● add (추가)

List에 요소를 추가하기 위해 add() 메서드를 사용합니다.
일반적으로 add() 메서드는 맨 뒤에 요소를 추가합니다. 즉, 리스트의 마지막 위치에 요소가 추가됩니다.

특정 위치에 삽입하고자 할 때는 add(index, element) 형태의 메서드를 사용합니다.
(index는 삽입할 위치의 인덱스, element는 추가할 요소)

 

 

 

● remove (제거)

List에서 요소를 삭제하기 위해 remove() 메서드를 사용합니다.


remove(index)를 사용하여 인덱스를 기준으로 요소를 삭제할 수 있습니다.
(index는 삭제할 요소의 인덱스)

remove(element)를 사용하여 해당 객체와 동일한 요소를 삭제할 수 있습니다.
(element는 삭제할 요소의 객체)

 

 

 

● 예시

import java.util.ArrayList;
import java.util.List;

public class ListAddDeleteExample {
    public static void main(String[] args) {
        List<String> pokemonList = new ArrayList<>();

        // 요소 추가
        pokemonList.add("피카츄");  // 맨 뒤에 추가
        pokemonList.add("꼬부기");
        pokemonList.add("파이리");

        // 요소 삭제
        pokemonList.remove(1);  // 인덱스 1에 해당하는 요소 삭제

        // 출력
        for (String pokemon : pokemonList) {
            System.out.println(pokemon);
        }
    }
}


● add 후 출력값
피카츄
꼬부기
파이리


● remove 후 출력값 (index 1번에 있는 꼬부기를 삭제)
피카츄
파이리

 

 

 

 

 

 

 

 

 

 

4)  헷갈리지 않기 1

 

Pokemon.java

public class Pokemon {
    private String name;
    private int level;

    public Pokemon(String name, int level) {
        this.name = name;
        this.level = level;
    }

    public String getName() {
        return name;
    }

    public int getLevel() {
        return level;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    @Override
    public String toString() {
        return "Pokemon: " + name + ", Level: " + level;
    }
}

 

Pikachu.java

public class Pikachu extends Pokemon {
    private String specialAbility;

    public Pikachu(String name, int level, String specialAbility) {
        super(name, level);
        this.specialAbility = specialAbility;
    }

    public String getSpecialAbility() {
        return specialAbility;
    }

    public void setSpecialAbility(String specialAbility) {
        this.specialAbility = specialAbility;
    }

    @Override
    public String toString() {
        return "Pikachu: " + getName() + ", Level: " + getLevel() + ", Special Ability: " + specialAbility;
    }
}

 

Main.java

import java.util.ArrayList;
import java.util.List;

public class Main {
    public static void main(String[] args) {
        List<Pokemon> myList = new ArrayList<>();

        Pikachu pikachu = new Pikachu("Pikachu", 10, "Static");
        myList.add(pikachu);

        // myList 출력
        for (Pokemon pokemon : myList) {
            System.out.println(pokemon);
        }
    }
}

 

List<Pokemon> myList = new ArrayList<>(); 에서

Pokemon은 클래스,

myList는 객체,

List<Pokemon>은 Pokemon 객체들의 리스트를 담을 수 있는 List를 선언한 것

 

 

 

 

 

 

 

 

 

5)  헷갈리지 않기 2

List<타입> arrayList = new ArrayList<>();

 

여기서 말하는 타입이란!?

 

 

● 기본데이터 타입

Integer: 정수를 저장하는 타입
Double: 실수를 저장하는 타입
Boolean: 논리값을 저장하는 타입
Character: 문자를 저장하는 타입

 

● 클래스 타입
String: 문자열을 저장하는 타입
Date: 날짜와 시간 정보를 저장하는 타입
Person: 사람의 정보를 저장하는 타입
Product: 상품 정보를 저장하는 타입

 

 

● 좀더 자세한 클래스 이름들

실제 코드를 작성하다보면 프로그램에 특화된 클래스 이름이 더 많이 사용될 수 있습니다. 

일반적인 데이터 타입보다는 프로젝트나 도메인에 따라서 더 구체적인 클래스 이름이 사용될 수 있습니다. 

 

1) 사용자 관리 시스템:
User: 사용자 정보를 저장하는 타입


2) 게시판 시스템:
Post: 게시물 정보를 저장하는 타입
Comment: 댓글 정보를 저장하는 타입


3) 주문 및 결제 시스템:
Order: 주문 정보를 저장하는 타입
Payment: 결제 정보를 저장하는 타입

 

User, Post, Comment 등과 같은 구체적인 클래스 이름은 위에서 언급한 기본 데이터 타입이나 클래스 타입에 속하지 않음!

이들은 그 자체로 클래스 이름이며, 특정 개념이나 엔티티를 나타내기 위해 사용됩니다!

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

2023.06.20 - [Java] - 객체 지향 프로그래밍

 

객체 지향 프로그래밍

객체 지향 프로그래밍 1) 객체 지향 프로그래밍(Object-Oriented Programming, OOP)의 개념 현실 세계의 사물을 프로그램으로 모델링하는 프로그래밍 방법입니다. 이 방법은 프로그램을 개별적인 객체들

devwarriorjungi.tistory.com

 

Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.