반응형

 

 

10분만 이 글에 투자해주시면

ArrayList를 List로 선언하는 이유를 이해시켜드리겠습니다..

(지적은 언제나 대환영입니다.)

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) (클릭🔗)

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅)  -> 본편

3. Set - HashSet, Map - HashMap 의 차이 (클릭🔗)

4. 추상클래스란? (클릭🔗)

 

 

 

 


ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅)

 

1편에서는 ListArrayList가 무슨 차이인지,

인터페이스와 구현체의 개념와 그 차이에 대해서 살펴보았습니다.

(해당 내용을 모르겠다면 클릭🔗)

 

 

List<String> stringList = new ArrayList<>();	// 1번
ArrayList<String> stringList = new ArrayList<>();	// 2번

이제 위 구문을 살펴보겠습니다.

 

 

stringList 변수는 ArrayList 구현체로 생성되었습니다.

ArrayList 클래스 구현 코드를 살펴보면, 아무 인자가 없을 때 작동하는 생성자가 존재할 것이고,

그것에 따라 ArrayList 객체를 생성했고, stringList에 할당시켰을 것입니다.

 

그런데, 어차피 ArrayList를 생성해서 사용할 것이라면

ArrayLIst 타입으로 선언하면 되지 않을까요? (1번)

굳이 List로 선언할 이유가 있을까요?? (2번)

 

하지만 2번을 사용하는 것이 널리 알려져 있습니다.

그 이유에 대해서 살펴봅시다.

 

 

Yo DJ~ spin that shxx~

 

 

 

 

1. List의 메서드는 문제 없이 사용 가능하다!

우선, List로 선언한 변수에 ArrayList를 구현체를 생성해 할당하면

List 안에 선언된 추상 메서드들을 ArrayList가 구현한 방식대로 사용할 수 있습니다.

 

이해를 돕기 위해 예시를 들겠습니다.

 

Listadd, size 라는 추상 메서드가 선언이 되었다고 가정하겠습니다.

그리고 ArrayListadd, size라는 메서드가 구현이 되었고,

추가로 addSize라는 메서드도 새로 구현이 되었다고 하겠습니다.

 

그럼 List 타입으로 선언된 stringListaddsize라는 메서드를 사용할 수 있습니다.

그리고 그것을 사용하면, ArrayList에서 구현한 방식대로 동작합니다.

 

하지만 여기서 문제가 발생하는데,

List에는 addSize라는 메서드가 선언되지 않았기 때문에,

stringListArrayListaddSize 메서드를 사용할 수 없습니다.

 

그렇지만, 대개 ArrayList에서 새로 선언한 메서드는 잘 사용되지 않고,

List 인터페이스에 선언된 메서드만으로 충분하기 때문에 큰 문제가 없다고 합니다!

 

 

 

 

2. (중요!) 다형성 부여 (+ 의존 관계 역전 원칙)

다형성이란 '하나의 객체가 여러 가지 타입을 가지는 것'을 의미합니다.

 

List<String> stringList = new ArrayList<>();


public int getFirstValueOfList(List stringList) {
	return stringList.어쩌구();
}

위 코드를 살펴보겠습니다.

stringListList 타입이지만, ArrayList로 구현되었습니다.

그런데, 자료의 추가, 삭제를 빠르게 하려고 LinkedList를 사용하고 싶어진다면 어떡할까요?

 

// List<String> stringList = new ArrayList<>();
List<String> stringList = new LinkedList<>();


public int getFirstValueOfList(List stringList) {
	return stringList.어쩌구();
}

구현체만 ArrayList에서 LinkedList로 변경해주면 끝입니다.

 

 

하지만, stringList의 타입이 List가 아닌 ArrayList였다면??

// List<String> stringList = new ArrayList<>();
ArrayList<String> stringList = new LinkedList<>(); // 컴파일 에러 발생


public int getFirstValueOfList(ArrayList stringList) {
	return stringList.어쩌구();
}

ArrayList 타입에는 LinkedList 구현체를 할당할 수 없어서 컴파일 에러가 발생합니다.

 

 

위와 같은 코드를 구현했다면,

코드에 보이는 ArrayList를 모두 LinkedList로 수정해야 합니다.

// List<String> stringList = new ArrayList<>();
LinkedList<String> stringList = new LinkedList<>();


public int getFirstValueOfList(LinkedList stringList) {
	return stringList.어쩌구();
}

 

코드가 복잡할수록 이 문제는 심각해집니다.

 

 

따라서 stringListList로 선언하고,

인자로 받을 때도 List로 받는 것입니다.

 

후에 stringList의 구현체가 변경되어도,

stringList와 관련한 메서드들을 수정할 필요가 없어지기 때문이죠.

 

이렇게 상위 개념으로 선언하고, 하위 개념을 생성해 할당하는 것을

업캐스팅(Up-casting)이라고 합니다.

 

(반대로 업캐스팅된 객체를 하위 개념 타입으로 변환하는 것은 다운캐스팅(Down-casting)이라고합니다.)

 

 

 

+ 추가내용)

이는 객체지향 SOLID 원칙D에 해당하는

의존 관계 역전 원칙(DIP : Dependency Inversion Principle)과도 연관이 있습니다.

 

저 원칙은 뜻이 되게 어려운데 (저에게는..)

저수준 모듈이 아닌 고수준 모듈에 의존해야 한다는 뜻을 가지고 있습니다.

 

즉, ArrayList가 아니라 List에 의존해야

다형성을 가질 수 있고, 다른 원칙을 위반하지 않을 수 있다는 것이죠.

관련 내용은 복잡하지만 중요해서, 추가로 찾아보기를 추천드립니다.

 

 

 


 

다음 아티클에서는

SetHashSet, MapHashMap의 차이에 대해서 다뤄보았습니다.

https://woojin.tistory.com/63

 

Set과 HashSet, Map과 HashMap의 차이 - 무조건 이해되는 List와 ArrayList의 차이(3)

(지적은 언제나 대환영입니다.) 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다. 1. 인터페이스와 구현체가 무엇인가? (List와 ArrayList의 차이) (클릭🔗) 2. ArrayList가 아닌 List 타

woojin.tistory.com

 

1, 2편 내용으로 충분히 이해되었을 내용이지만,

복습이 필요하시다면 읽어봐주세요.

 

감사합니다!

 

 

 

 

 

 

 

 

 

반응형
반응형

 

 

 

 

10분만 이 글에 투자해주시면

List, ArrayList, 인터페이스, 구현체 이해시켜드리겠습니다..
(지적은 언제나 대환영입니다.)

본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있습니다.

 

1. 인터페이스와 구현체가 무엇인가?  (List와 ArrayList의 차이) -> 본편

2. ArrayList가 아닌 List 타입으로 선언하는 이유 (업캐스팅) (클릭🔗)

3. Set - HashSet, Map - HashMap 의 차이 (클릭🔗)

4. 추상클래스란? (클릭🔗)

 

 

 

 

 


List<String> stringList = new ArrayList<>();

위 코드를 처음 보고 이런 생각이 들었습니다.

ArrayList<String> stringList = new ArrayList<>();

이렇게 바꿔야하는 거 아닌가?

 

어차피 ArrayList를 사용할 건데, 왜 타입은 List로 지정하는 거지?

이렇게 생긴 의문은 ListArrayList의 차이, List는 뭐였더라.. 등등 겉잡을 수 없는 의문 폭탄에 불을 붙였습니다.

 

 

 

누구에게는 상당히 쉬운 주제일 수 있겠으나,

자바 문법을 가볍고 빠르게 공부한 저에게는

전혀 이해가 되지 않는 문제였습니다.

 

하지만 이번 공부를 통해 인터페이스와 구현체에 관한 개념은 완벽하게 이해했다고 자부합니다.

관련해서 찾아보고 이해한 내용을 공유하고자 합니다.

 

 

 

 

 

 

Trust me, Follow me. ㅋㅋ

 

 

 


 

인터페이스(List)와 구현체(ArrayList)

 

List인터페이스이고, ArrayList클래스입니다.

그 차이를 알기 위해, 정의된 곳으로 가서 살펴볼 필요가 있습니다.

 

IntelliJ(또는 Eclipse)에서 Listimport한 후

List에 커서를 가져다 대고 cmd+B(ctrl+B)를 클릭하면, (또는 cmd + 마우스 좌클릭)

해당 클래스가 정의된 곳으로 이동합니다.

 

Let's go together~

List가 정의된 곳으로 가보자
List가 구현된 부분! interface로 선언되었음을 알 수 있다.
ArrayList가 구현된 부분..?

어라.. ArrayList는 이상하다..! 왜 두 번 구현되어 있지..? (사실 두 번보다 더 많다.)

게다가 classinterface로도 선언되지 않았습니다.

 

왜냐면, 해당 부분은 생성자를 구현한 부분이기 때문입니다.

위로 올라가면 ArrayList의 선언이 나옵니다.

ArrayListAbstractList를 상속받은 클래스입니다. AbstractList도 들어가봅시다.

 

implements List !!

그렇습니다.

결국 ArrayLisstList라는 인터페이스를 구현(implements)한 클래스입니다.

(중간을 매개하는 AbstractList 클래스는 맨 뒤 4번에서 다루겠으니, 잠시 잊어둡시다.)

 

여기서, 클래스(class)와 인터페이스(interface)의 차이를 짚고 넘어가겠습니다.

(필자는 둘의 차이를 정확히 알지 못했습니다.)

 

 

클래스(class) vs 인터페이스(interface)

클래스와 인터페이스는 모두 내부에 메서드를 가집니다.

하지만 클래스는 메서드의 body가 존재해서 그 내용이 구현된 반면,

인터페이스는 body가 존재하지 않습니다! (default, static 메서드는 예외)

 

여기까지는 필자도 이미 알고 있었지만, 왜 그렇게 되어 있는지는 몰랐습니다.

 

List 인터페이스 내부의 size 메서드 -> 설명만 주석으로 달려 있고, 구현이 안 되어 있다.
ArrayList 클래스 내부의 add 메서드 -> 구현이 되어 있다!

 

 

그것은 인터페이스와 클래스의 역할이 다르기 때문입니다.

 

아래에서는 List 인터페이스가 add, size 메서드 2개만 가지고 있다고 단순하게 가정하겠습니다.

 

List 인터페이스는 List가 갖춰야 할 기본 규격을 뜻합니다.

"List라고 하면, 자고로 add, size 메서드 정도는 있어야 해" 라고 알려주는 가이드와도 같습니다.

여기서, List안에 존재하는 add, size 메서드는 추상 메서드 라고 합니다.

구체적으로 기능이 구현된 메서드가 아니라, 그 존재만 추상적으로 선언된 것입니다.

 

ArrayListList 인터페이스를 구현(implements)한 클래스입니다.

List라는 규격에 따라, 실제로 add, size를 구현해서 사용하게끔 만들어졌다는 뜻입니다.

 

ArrayList 뿐만 아니라 LinkedList, VectorList 인터페이스 규격에 맞게 설계된 많은 클래스들이 존재합니다.

이런 클래스들을 LIst의 구현 객체 또는 구현체 라고 부릅니다.

 

ArrayList는 그중 배열의 성질을 활용하기 위해 만들어진 하나의 구현체일 뿐인 것이죠.

 

 

이렇게 우리는

인터페이스(List)와 구현체(ArrayList, 클래스)의 뜻을 이해했고,

List ArrayList가 어떤 차이를 가지는 지도 파악했습니다.

 

 

List<String> stringList = new ArrayList<>();

그렇다면, 정말 많이 볼 수 있는 위 구문에서

stringList 변수는 List로 선언되고 ArrayList로 생성된 이유는 무엇일까요?

 

 

 

다음 아티클에서 설명드리겠습니다!! (링크 👇)

https://woojin.tistory.com/62

 

ArrayList를 List로 선언하는 이유(업캐스팅) - 무조건 이해되는 List와 ArrayList의 차이(2)

10분만 이 글에 투자해주세요. ArrayList를 List로 선언하는 이유를 이해시켜드리겠습니다. 본 아티클 시리즈를 정독하면, 아래 의문에 답을 얻을 수 있다. 1. 인터페이스와 구현체가 무엇인가? (List

woojin.tistory.com

 

 

 

 

 

 

 

 

 

 

 

반응형

+ Recent posts