[java] 차이점은 무엇입니까? Java 제네릭의 Object?

Java 제네릭을 올바르게 사용하기 위해 일부 코드를 정리할 수 있도록 Eclipse를 사용하고 있습니다. 대부분 유추 유형의 훌륭한 작업을 수행하지만 유추 유형이 가능한 한 일반적인 경우가 있습니다. Object. 그러나 Eclipse는 Object 유형과 ‘?’유형 중에서 선택할 수있는 옵션을 제공하는 것 같습니다.

차이점은 무엇입니까?

HashMap<String, ?> hash1;

HashMap<String, Object> hash2;



답변

HashMap<String, String>일치 Map<String, ?>하지만 일치 하지 않는 인스턴스 Map<String, Object>. Strings에서 무엇이든에 대한 맵을 허용하는 메소드를 작성한다고 가정하십시오 .

public void foobar(Map<String, Object> ms) {
    ...
}

을 (를) 제공 할 수 없습니다 HashMap<String, String>. 당신이 쓰는 경우

public void foobar(Map<String, ?> ms) {
    ...
}

효과가있다!

Java의 제네릭에서 때때로 잘못 이해되는 List<String>것은의 하위 유형이 아니라는 것입니다 List<Object>. (그러나 String[]실제로의 하위 유형은 Object[]제네릭과 배열이 잘 혼합되지 않는 이유 중 하나입니다 (Java의 배열은 공변량이고 제네릭은 변하지 않습니다 )).

샘플 : 당신이 받아들이는 방법을 쓰고 싶다면 List의의 InputStream의와의 하위 유형 InputStream, 당신은 쓸 것

public void foobar(List<? extends InputStream> ms) {
    ...
}

그런데 Joshua Bloch의 Effective Java 는 Java에서 그렇게 간단하지 않은 것을 이해하고 싶을 때 훌륭한 리소스입니다. (위의 질문은이 책에서도 잘 설명되어 있습니다.)


답변

이 문제를 생각하는 또 다른 방법은

HashMap<String, ?> hash1;

에 해당

HashMap<String, ? extends Object> hash1;

이 지식을 Java Generics and Collections의 섹션 2.4의 “Get and Put Principle”과 결합하십시오 .

Get and Put Principle : 구조에서 값을 가져올 때만 확장 와일드 카드를 사용하고 구조에 값을 넣을 때는 슈퍼 와일드 카드를 사용하고 가져오고 넣을 때 와일드 카드를 사용하지 마십시오.

와일드 카드가 더 이해하기 쉬울 것입니다.


답변

그것이 Collection<Object>유형의 객체를 포함하는 일반 컬렉션 Object이지만 Collection<?>모든 유형의 컬렉션의 슈퍼 유형 이라는 것을 기억하면 쉽게 이해할 수 있습니다 .


답변

공분산 위의 답변은 대부분의 경우에 적용되지만 한 가지는 누락됩니다.

“?” 클래스 계층 구조에 “Object”를 포함합니다. String은 Object의 유형이고 Object는?의 유형이라고 말할 수 있습니다. 모든 것이 Object와 일치하는 것은 아니지만 모든 것이?와 일치합니다.

int test1(List<?> l) {
  return l.size();
}

int test2(List<Object> l) {
  return l.size();
}

List<?> l1 = Lists.newArrayList();
List<Object> l2 = Lists.newArrayList();
test1(l1);  // compiles because any list will work
test1(l2);  // compiles because any list will work
test2(l1);  // fails because a ? might not be an Object
test2(l2);  // compiled because Object matches Object


답변

Map<String, ?>값이 어떤 유형인지 알지 못하므로 에 아무 것도 넣을 수 없습니다 .

당신은 어떤 개체를 넣을 수 있습니다 Map<String, Object>값이로 알려져 있으므로Object .


답변

변수 로 키 의 값과 모든 유형의 값을 가질 수 있음을 선언 hash1으로 선언 합니다.HashMap<String, ?>hash1HashMapString

HashMap<String, ?> map;
map = new HashMap<String, Integer>();
map = new HashMap<String, Object>();
map = new HashMap<String, String>();

변수 map 가 해시 맵을 저장할 수 있으므로 위의 모든 것이 유효 합니다. 해당 변수는 보유하고있는 해시 맵의 값 유형이 무엇인지 상관하지 않습니다.

와일드 카드를 갖는 않습니다 되지 그러나, 당신은지도에 모든 유형의 개체를 만들어 보자. 사실, 위의 해시 맵을 사용하면 map변수를 사용하여 아무것도 넣을 수 없습니다 .

map.put("A", new Integer(0));
map.put("B", new Object());
map.put("C", "Some String");

Java가 HashMap의 Value 유형을 알지 못하므로 위의 모든 메소드 호출로 인해 컴파일 타임 오류가 발생합니다. map 합니다.

여전히 해시 맵에서 값을 얻을 수 있습니다. “값의 유형을 모르지만”(변수 안에 어떤 유형의 해시 맵이 있는지 모르기 때문에) 모든 것이 서브 클래스이고 Object맵에서 나가는 것이 무엇이든 말할 수 있습니다. Object 유형이됩니다.

HashMap<String, Integer> myMap = new HashMap<>();// This variable is used to put things into the map.

myMap.put("ABC", 10);

HashMap<String, ?> map = myMap;
Object output = map.get("ABC");// Valid code; Object is the superclass of everything, (including whatever is stored our hash map).

System.out.println(output);

위의 코드 블록은 콘솔에 10을 인쇄합니다.


따라서 마무리하려면 다음 HashMap과 같이 유형이 무엇인지 신경 쓰지 않을 때 와일드 카드를 사용하십시오 (예 : 중요하지 않음) HashMap.

public static void printHashMapSize(Map<?, ?> anyMap) {
    // This code doesn't care what type of HashMap is inside anyMap.
    System.out.println(anyMap.size());
}

그렇지 않으면 필요한 유형을 지정하십시오.

public void printAThroughZ(Map<Character, ?> anyCharacterMap) {
    for (int i = 'A'; i <= 'Z'; i++)
        System.out.println(anyCharacterMap.get((char) i));
}

위의 방법에서 우리는 Map의 키가임을 알아야합니다. Character그렇지 않으면 값을 얻는 데 사용할 유형을 알 수 없습니다. toString()그러나 모든 객체에는 메소드가 있으므로 맵에는 값에 대한 모든 유형의 객체가있을 수 있습니다. 여전히 값을 인쇄 할 수 있습니다.


답변