728x90

<?> 는 와일드카드 타입이다. 즉 모든 타입을 의미한다. 주로 타입 인자를 알지 못할 때 쓰인다.

그러면 그냥 List와 List<?>의 차이는 무엇일까?

List<?> 를 매개변수로 사용하는 메서드는 List의 원소를 읽는 것은 가능하지만, 쓰는 것은 불가능하다.

 

읽기

List, List<?> 둘 다 파라메터로 받아 와서 읽는 것은 가능하다.

 

 

쓰기

코드상에서 바로 에러를 잡을 수 있다.(컴파일 전 타입체크)

List<?>는 write를 하지 못한다는 것을 알 수 있다.

'언어 > 자바' 카테고리의 다른 글

[JAVA] List<?> 와 List<Object>의 차이  (2) 2022.09.21
728x90

의심할바 없이 제네릭은 자바에서 헷갈리는 것중 하나입니다. 그리고 매일 자바로 프로그래밍을 하지 않는다면 쉽게 잊어버릴 수 있는 개념이기도 합니다. 예를 들어 List<?> 와 List<Object>는 비슷해 보입니다. 그러나 약간 다릅니다. List<?>는 기본적으로 어떤 타입(any type)의 List 입니다. List<String>, List<Integer> 등을 할당할 수 있습니다.

기본적으로 List<?>는 밑에와 같이 할당할 때 까지는 모릅니다.

List<?> list = new List<String>();

 

그러면 List<Object>로 돌아와봅시다. 이는 List<String>과 별다른 차이가 없습니다. String 대신에 Object를 받아들일 뿐입니다. 모든 클래스는 Object를 상속을 받고 있습니다. 그러면 본질적으로 Object는 어떤 객체든 담을 수 있다는 얘기입니다.

그런데 자세히 읽어보시면 List<?>는 어떤 List 타입을 할당받을 수 있고, List<Object>는 어떤 Object 타입을 저장할 수 있습니다. 이것이 진짜 List<?>와 List<Object>의 차이입니다.

예시를 한번 봐야겠지요?

 

제가 List<?>는 어떤 타입(any type)의 List를 할당할 수 있다고 했지만 List<Object>에는 그렇게 할 수 없습니다. 이와 같이 String, Integer, Double 등 List<Object>에 넣을 수 있는 것들을 다 넣을 수 있습니다. 그러나 List<?>에는 불가능합니다. 왜냐하면 <?>은 타입이 unknown이기 때문입니다.

import java.util.ArrayList;
import java.util.List;

public class Demo {

public static void main(String[] args) {

        printElements(new ArrayList<String>()); // OK
        printElements(new ArrayList<Integer>()); // OK

        printObjects(new ArrayList<String>());
        // NOT OK compile time error

        printObjects(new ArrayList<Integer>());
        // NOT OK compile time error
    }

public static void printElements(List<?> listOfUnknownType) {
        listOfUnknownType.add("abc"); // compile time error

for (Object o : listOfUnknownType) {
            System.out.println(o); // OK
        }
    }

public static void printObjects(List<Object> listOfObjects) {
        listOfObjects.add("abc"); // OK
        listOfObjects.add(101); // OK

for (Object o : listOfObjects) {
            System.out.println(o); // OK
        }
    }
}

위 코드를 보시면 ArrayList<String>와 ArrayList<Integer>는 printElements() 함수를 통과를 하지만 printObjects() 함수는 통과하지 못하는 것을 보실 수 있습니다. 왜냐하면 String과 Integer은 Object와 다른 타입이기 때문입니다. 부모-자식 상으로는 같지만, 제네릭은 불변 타입이기 때문에 상속관계를 무시하기 때문에 다르다고 인식이 됩니다. 첫번째 함수인 printElements()를 통과하는 것이 가능했던 이유는 어떤 타입을 받을 수 있는 List<?>이었기 때문입니다.

 

결국에는 printObjects(List<Object> listOfObject) 는 에러를 던지게 되는거죠 왜냐하면 Object 타입만 받을 수 있기 때문입니다.

만약에 단순 읽는 작업을 하면 List<?>와 List<Object>의 기능은 같습니다. 그런데 objects 를 추가할때는 List<?>는 에러가 납니다. 왜냐하면 unknown 이기 때문입니다.

 

List<?>의 경우 컴파일러는 List의 타입이 유효한지 모릅니다. 그래서 타입안정성을 보장할 수 없기 때문에 에러를 던집니다. 그런데 List<Object>의 경우에는 컴파일러가 List의 타입이 Object인것을 정확히 알기 때문에 String, Integer, Double 등을 할당할 수 있습니다.

 

그래서 List<?>와 List<Object>의 차이는 코더가 무엇을 하느냐에 달려있습니다. 만약 객체를 읽을때 (List에서 객체를 출력할때)  List<?>, List<Object> 둘다 사용해도 좋습니다. 그런데 요소를 추가할때는 List<Object>를 사용해야합니다. 만약 제네릭 함수를 작성중일 때 어떠한 타입의 list를 함수의 매개 변수로 받고싶을때는 List<?>를 사용합니다.

 

 

https://okky.kr/articles/354841

'언어 > 자바' 카테고리의 다른 글

List<?> 와 List 의 차이  (0) 2023.05.03

+ Recent posts