Java LinkedList - 직접 구현하기 3

직접 구현한 연결리스트에서 추가로 제네릭 도입하여 타입 안정성을 높이고, Node 객체는 외부에서 사용하지 않으므로 내부에서 사용하도록 중첩 클래스로 만든다.

  • 제네릭 도입
  • 중첩 클래스 사용

ClinkedList.class

public class CLinkedList<E> {
    Node<E> first;
    int size;

    public void add(E e) {
        Node<E> newNode = new Node<>(e);
        if (first == null) {
            // 노드를 처음으로 사용한 경우에만 수행함
            first = newNode;
        } else {
            // 노드가 있는 경우 수행
            Node<E> lastNode = getLastNode();
            lastNode.next = newNode;
        }
        size++;
    }

    public void add(int index, E e) {
        Node<E> newNode = new Node<>(e);

        if (index == 0) {
            newNode.next = first;
            first = newNode;
        } else {
            Node<E> prevNode = getNode(index-1);
            newNode.next = prevNode.next;
            prevNode.next = newNode;
        }
        size++;
    }

    public E remove(int index) {
        Node<E> retNode;
        E item;
        if (index == 0) {
            retNode = first;
            first = first.next;
        } else {
            Node<E> prevNode = getNode(index-1);
            retNode = prevNode.next;
            prevNode.next = prevNode.next.next;
        }
        item = retNode.item;
        retNode.item = null;
        retNode.next = null;
        size--;
        return item;
    }

    private Node<E> getLastNode() {
        Node<E> n = first;
        while (n.next != null) {
            n = n.next;
        }
        return n;
    }

    public E set(int index, E element) {
        Node<E> n = getNode(index);
        E oldValue = n.item;
        n.item = element;
        return oldValue;
    }

    public E get(int index) {
        Node<E> node = getNode(index);
        return node.item;
    }

    private Node<E> getNode(int index) {
        Node<E> n = first;
        for (int i = 0; i < index; i++) {
            n = n.next;
        }
        return n;
    }

    public int indexOf(E o) {
        int index = 0;
        for (Node<E> n = first; n != null; n = n.next) {
            if (o.equals(n.item)) {
                return index;
            }
            index++;
        }
        return -1;
    }

    public int size() {
        return size;
    }

    @Override
    public String toString() {
        return "CLinkedList{" +
                "first=" + first +
                ", size=" + size +
                '}';
    }

    private static class Node<E> {
        E item;
        Node<E> next;

        public Node(E item) {
            this.item = item;
        }

        @Override
        public String toString() {
            StringBuilder sb = new StringBuilder();
            Node<E> n = this;
            sb.append("[");
            while (n != null) {
                sb.append(n.item);
                if (n.next != null) {
                    sb.append("->");
                }
                n = n.next;
            }

            sb.append("]");
            return sb.toString();
        }
    }
}
  • CLinkedList<E> 제네릭 클래스로 선언
  • Object 타입이 없도록 타입 및 파라미터 <E> 로 변경
  • 정적 중첩 클래스로 새로 Node<E> 제네릭 타입으로 선언

중첩 클래스 사용

  • 클래스 안에 클래스로 선언한 것이 중첩 클래스.
  • 중첩 클래스는 중첩 클래스 안에서만 사용.
  • Node 클래스는 CLinkedList 안에서만 사용하고 외부에 공개할 이유 없음.
  • 중첩 클래스는 클래스 안에 있으므로 선언을 은닉함.
  • 외부의 Node 클래스보다 내부의 Node 클래스로 우선 사용으로 패키지 관리 수월.

Main.class - 출력하기

System.out.println("** String LinkedList **");
CLinkedList<String> strList = new CLinkedList<>();
strList.add("A");
strList.add("B");
strList.add("C");
String str = strList.get(0);
System.out.println(str);
System.out.println(strList);
System.out.println(strList.first);
System.out.println();

System.out.println("** Integer LinkedList **");
CLinkedList<Integer> intList = new CLinkedList<>();
intList.add(100);
intList.add(200);
intList.add(300);
Integer num = intList.get(0);
System.out.println(num);
System.out.println(intList);
System.out.println(strList.first);

** String LinkedList **
A
CLinkedList{first=[A->B->C], size=3}
[A->B->C]

** Integer LinkedList **
100
CLinkedList{first=[100->200->300], size=3}
[A->B->C]