[Java] 제네릭 - Collection/ Wrapper 객체

김세림·2024년 4월 30일

Java

목록 보기
20/24
post-thumbnail

제네릭 - Collection/ Wrapper 객체


Collection - List

Collection의 List에 대한 기본적인 설명은 이전 포스트인 List여기에서 설명했었지만, 이번에는 더 많은 내용들을 다루어보려고한다.

List, 배열 예시

  • 리스트
    • 추상적 자료구조 (추상적으로 interface를 만들어 놓은 것)
    • 순서가 있고 중복을 허용함.
  • 배열
    • 프로그래밍 언어에서 지원하는 자료형
    • 순서대로 번호가 붙은 원소들이 연속적인 형태로 구성된 구조

배열

  • 리스트가 어디에 있든지, 첫칸의 주소를 알면 바로 접근할 수 있다.
  • 첫칸의 주소가 2라고 해보자, 그럴때 3번째 원소의 접근하고 싶다면 2에 3을 더한 5가 3번째 원소의 주소이다.
  • 이런식으로 검색은 빠르지만 추가 삭제가 매우 느리다.
  • 중간에 값을 삭제하고 싶다면 중간에 값을 삭제 한 후 한칸씩 앞으로 이동해주어야하기 때문
    => 결론 : 검색에는 유리하고, 수정/삭제는 불리한 자료구조

List

  • 추상적 자료구조인 리스트는 개념적으로 보통 다음 연산들을 지원한다.
    • 빈 리스트를 만드는 연산
    • 리스트가 비어있는지 확인하는 연산
    • 리스트의 앞에 원소를 삽입하는 연산
    • 리스트의 뒤에 원소를 삽입하는 연산
    • 리스트의 제일 첫 원소를 알아보는 연산
    • 리스트의 첫 원소를 제외한 나머지 리스트를 알아보는 연산

  • 리스트의 개념적인 명세는 자바에서 실제로 위와 같이 구현되어있다.
    • 즉 실제 존재하는 현실의 개념인 리스트를 interface 코드 내부에 정리
    • List 인터페이스를 구현하는 구현체들은 List의 명세를 모두 구현해야한다.
    • 즉 List 인터페이스의 구현체들이 List의 속성을 가지게 됩니다.

List에서의 제네릭

// 실제 java.util의 List 코드
public interface List<E> extends Collection<E> {
		int size();
    boolean isEmpty();
		...
		boolean addAll(Collection<? extends E> c);
		boolean add(E e);
		...
}

위 코드의 List인터페이스는 제네릭 인터페이스이다.
E는 타입변수로 리스트에 저장되는 데이터 타입을 말한다.
add()메소드는 리스트 인터페이스에 지정한 E라는 타입을 추가하는데 사용한다.
여기서 addAll() 메소드를 조금 더 설명하겠다.(조금 복잡..)

  • 메서드의 인자에 조건이 두 개.
    1. Collection 타입에 속하는 것,
    2. List의 타입 변수 E의 자손 클래스를 원소로 가지고 있을 것
  • 이 두 가지 조건을 만족하는 뭔가를 넘겨받은 경우에만, addAll로 일괄적으로 추가할 수 있다.

Collection 다시보기

  • Collection(집합적 자료)라는 속성은 Iterable(순회 가능)이라는 속성을 상속받고 있다.(이전 레시피만들기에서 사용했음.)
  • Collection의 하위 ‘속성’으로는 List, Queue, Set 등이 있다.
  • List의 실제 구현체들은 Arr, Linked, Vector, Stack
  • 상황에 맞는 적절한 자료구조를 택하는 방법은 아래와 같다.
    • 인터페이스, 즉 속성에서는 코드를 보고 “어떠한 일을 해주는지”를 알 수 있다.
    • 클래스, 즉 실제 구현체에는 위의 어떠한 일을 “어떻게 해주는지” 알 수 있다.
    • 즉 내가 지금 데이터를 다루는데 필요한 기능을 어떠한 것들이 해주는 지는 인터페이스에서 찾고, 어떠한 방식으로 해줘야 유리할지는 실제 구현체를 보고 판단하면 된다.

Wrapper 객체

wrapper에 대해서도 이전 포스트 wrapper 클래스 변수로 설명했던 적이 있다.
왜 이것을 쓰느냐에 대해서는 객체지향의 더 많은 기능을 사용할 수 있다.라고 표현했었는데 그에 대해 더 자세히 설명해보도록 하겠다.

왼쪽 기본형같은 경우에는 값 이상의 일을 하지않기때문에 원시타입 그대로를 사용한다. (객체화 시키지않음)
하지만 기본형의 자료들도 추상화가 필요한 개념이 있을 수 있지 않겠는가!
(소수, 반올림...)
이럴때를 대비해 객체화를 해둔 것이 바로 wrapper class이다.
(값만을 사용할때가 아닌 객체의 기능이 필요할때 사용한다는 것이다.)

이전포스트에서는 박싱, 언박싱에 대해서만 말을 했었는데 오토박싱과 오토언박싱도 예시를 보여주겠다.

Integer num = new Integer(17);  // Boxing
int n = num.intValue(); // UnBoxing

Character ch = 'X'; // AutoBoxing
char c = ch; // AutoUnBoxing

위 차이를 보면 그냥 기본형변수처럼 선언하고 초기화를 하는 것을 의미한다.
또한 언박싱도 기본형 자료구조인 char로 c변수를 선언하고 초기화하는 부분이 wrapper class여도 자동으로 언박싱된다.

이런식으로 박싱해서 객체화된 원시 값들은 클래스처럼, 구현되어있는 메소드들을 자유롭게 이용할 수 있고, 객체만 할 수 있는 것들도 할 수 있게 된다.

0개의 댓글