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가 구현한 방식대로 사용할 수 있습니다.
이해를 돕기 위해 예시를 들겠습니다.
List에 add, size 라는 추상 메서드가 선언이 되었다고 가정하겠습니다.
그리고 ArrayList에 add, size라는 메서드가 구현이 되었고,
추가로 addSize라는 메서드도 새로 구현이 되었다고 하겠습니다.
그럼 List 타입으로 선언된 stringList는 add와 size라는 메서드를 사용할 수 있습니다.
그리고 그것을 사용하면, ArrayList에서 구현한 방식대로 동작합니다.
하지만 여기서 문제가 발생하는데,
List에는 addSize라는 메서드가 선언되지 않았기 때문에,
stringList는 ArrayList의 addSize 메서드를 사용할 수 없습니다.
그렇지만, 대개 ArrayList에서 새로 선언한 메서드는 잘 사용되지 않고,
List 인터페이스에 선언된 메서드만으로 충분하기 때문에 큰 문제가 없다고 합니다!
2. (중요!) 다형성 부여 (+ 의존 관계 역전 원칙)
다형성이란 '하나의 객체가 여러 가지 타입을 가지는 것'을 의미합니다.
List<String> stringList = new ArrayList<>();
public int getFirstValueOfList(List stringList) {
return stringList.어쩌구();
}
위 코드를 살펴보겠습니다.
stringList는 List 타입이지만, 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.어쩌구();
}
코드가 복잡할수록 이 문제는 심각해집니다.
따라서 stringList를 List로 선언하고,
인자로 받을 때도 List로 받는 것입니다.
후에 stringList의 구현체가 변경되어도,
stringList와 관련한 메서드들을 수정할 필요가 없어지기 때문이죠.
이렇게 상위 개념으로 선언하고, 하위 개념을 생성해 할당하는 것을
업캐스팅(Up-casting)이라고 합니다.
(반대로 업캐스팅된 객체를 하위 개념 타입으로 변환하는 것은 다운캐스팅(Down-casting)이라고합니다.)
+ 추가내용)
이는 객체지향 SOLID 원칙의 D에 해당하는
의존 관계 역전 원칙(DIP : Dependency Inversion Principle)과도 연관이 있습니다.
Oct 28, 2022 8:15:45 PM org.junit.platform.launcher.core.EngineDiscoveryOrchestrator lambda$logTestDescriptorExclusionReasons$7
INFO: 0 containers and 10 tests were Method or class mismatch
에러 상황
- 테스트 코드 중 특정 클래스만 실행할 때 발생했다.
에러 이유
작성된 테스트 코드 중 특정 클래스만 실행했다는 경고문이다.
실제로 실행시킨 테스트 코드는 잘 실행되었으며, 전체 테스트 코드 실행 시 해당 경고문이 발생하지 않았다.
테스트에는 아무 문제가 없었다.
또한, 빌드할 때 JUnit으로 테스트가 진행 되어야 하는데 Gradle로 되어서 발생하는 것이라고 한다.
Project language level은 IntelliJ의 editor(편집기)와 java compiler가 사용할 language level을 설정한다.예를 들어, JDK 1.7을 사용하고 있지만 java 코드가 JDK 1.6과 호환되도록 하려면language level을실제 JDK 지원(JDK 1.7의 경우 7.0)보다 낮은 6.0으로 설정하면 된다.
Java 컴파일러 명령인javac의 옵션을 보면 -source 및 -target 옵션을 통해 Java의 대체 버전을 기준으로 컴파일할 수 있음을 알 수 있다. 이를 통해 Project language level은 IntelliJ에게 특정 Java 언어 버전에서 제공된 Java SDK를 사용하도록 지시한다. 그래서 Java 7이 설치되어 있어도 language level을 6.0으로 설정할 수 있고, IntelliJ는 Java 7 대신 Java 6을 기준으로 코드를 확인하고, suggestion을 제공하며, 컴파일한다.