Java Collection Interface에 대하여

김상엽·2020년 9월 26일
0

Java

목록 보기
1/1

자바는 자료구조를 Collection패키지를 이용해 제공합니다. Collection 패키지의 내부 구조는 어떻게 되어있는지,
어떻게 설계되어있는지 Docs와 실제의 소스코드를 찾아보면서 이번 Post에 정리해보려고 합니다.

Collection

The root interface in the collection hierachy. A collection represents a group of objects, known as its element. Some collections allow duplicate elements and others do not. Some are ordered and others unordered.

공식 Docs의 Collection에 대한 설명입니다. 간략하개 Collection은 Object의 그룹이며, Object의 중복, 순서는 있을수도 있고 없을수도 있다고 합니다. 위와 같은 특성에 대한 세부적인 구현은 Collection에서 다루는것이 아닌 SubInterface에서 다룹니다.

public interface Collection<E> extends Iterable<E> {
	int size();
	boolean isEmpty();
	boolean contains();
	Iterator<E> iterator();
	Object[] toArray();
	boolean add(E e);
	boolean remove(Object o);
  //containsAll, removeAll, removeIf, stream, parallelStream, spliteator...
}

위의 Code는 Collection 인터페이스의 정의입니다. 여기서 개인적으로 궁금한점이 있었습니다. 왜 add메서드는 Generic으로 Parameter를 받는데, remove는 Object Type으로 받는가?

위의 답은 stackoverflow에서 찾을 수 있었습니다.
왜 add와 remove의 파라미터가 다른가?

add와 remove의 역할이 서로 다르다는것입니다.

add메서드는 잘못된 타입의 객체를 넣으려고 할 경우 컴파일 에러가 발생합니다. (당연히 Collection에서 Generic을 받게 정의를 해두었으니 컴파일에러가 발생하는것이 당연합니다.)
그렇다면 remove메서드는 왜 잘못된 타입의 객체를 삭제하려고 할때 컴파일에러가 발생하지 않는가?
remove는 Object를 기준으로 인자를 받습니다. 이때 remove의 기준은 바로 동일성 (==)이 아닌 동등성 (equals)의 기준으로 Collection에서 객체를 삭제합니다. 즉 삭제하려는 객체가 타입이 다르더라고 equals의 메서드 리턴 결과가 true, 즉 동등하다면 삭제할 수 있다는것입니다.

Iterable

Implementating this interface allows an object to be the target of the enhanced for-statement (for each)

Foreach를 사용할 수 있게 하기 위한 인터페이스 입니다. 즉 해당 Object를 순회할 수 있는가? 이러한 특성이 Object에 존재하는가?에 대한 인터페이스라고 생각할 수 있습니다.

Collection의 상위 인터페이스로는 Iterable를 상속받고 있습니다. 즉 Collection을 구현하는 모든 클래스는 for-each문을 사용할 수 있습니다.

Collection : All known Subinterfaces

Deque, List, Queue, Set, SortedSet

위의 자료구조들은 구현체가 아닌 Interface입니다. 즉 해당 인터페이스를 구현하려면 어떠한 기능이 필요한지, 그와 관련된 스펙이 정의되어 있습니다.

대표적인 Collection인 List

Interface List의 추상 클래스 AbstarctList가 대부분의 기능을 구현하고 있습니다. 실제로 MyList라는 클래스를 만들어서 해당 추상클래스를 상속받으면 구현해야할 기능이 2가지 밖에 되지않습니다.

class MyList<T> extends AbstractList<T> {
    @Override
    public T get(int index) {
        return null;
    }
    @Override
    public int size() {
        return 0;
    }
}

이 말은 즉슨 제가 이해하기에 get메서드와 size메서드만 구현하면 MyList를 List처럼 사용할 수 있다는 의미처럼 들립니다. 하지만
그렇지 않습니다. AbstractList에서는 add 메서드를 호출하면 항상 예외를 던지도록 설계해놓았기 때문입니다.

즉 저는 AbstarctList를 상속해도 add라는 메서드를 오버라이딩하여 구현해야지만 제가 설계한 List를 사용할 수 있다는 말입니다.
여기서 좀 의아한게 왜 Abstarct에서 add 메서드를 정의해놓았을까?라는 의문이 들었습니다. 사실 add 또는 remove는 어떻게 List를 구현하는지에 따라 구현방법이 달라질것이기 때문에 Abstract에서 정의할 수 도 없었겠지만 굳이 정의를 해놓은 이유가 궁금했습니다.
정의를 하지 않았다면 AbstarctList를 상속받을때, 개발자가 좀더 명확하게 자신이 구현해야하는 기능을 알 수 있었을 것입니다.

List를 구현한 여러가지 잘 알려진 클래스들 : ArrayList, LinkedList, Stack, Vector

더 많은 클래스들이 존재하지만 대표적인 클래스들만 썼습니다. 위의 4개의 클래스들은 전부 세부적인 구현은 다르지만 List의 기능을 동작하는
클래스들입니다. 그렇기때문에 List를 사용하고 싶다면 위의 4개중에 어떤것을 사용하더라도 상관은 없지만, 더 세부적으로 구현된 기능이 필요하다면 해당 타입으로 선언된 객체를 사용해야할것입니다.

profile
기록을 습관화 하는 개발자

0개의 댓글