List <MyType>을 인스턴스화하는 방법?


87

이런 종류의 일을 어떻게 할 수 있습니까? 나는 확인할 수 (obj instanceof List<?>)있지만 그렇지 않은 경우 (obj instanceof List<MyType>). 이렇게 할 수있는 방법이 있습니까?



답변:


49

제네릭의 컴파일 타임에 데이터 유형이 삭제되기 때문에 불가능합니다. 이 작업을 수행하는 유일한 방법은 목록이 보유하는 유형을 보유하는 일종의 래퍼를 작성하는 것입니다.

public class GenericList <T> extends ArrayList<T>
{
     private Class<T> genericType;

     public GenericList(Class<T> c)
     {
          this.genericType = c;
     }

     public Class<T> getGenericType()
     {
          return genericType;
     }
}

감사합니다. 두 항목을 모두 확인하고 확인하기 위해 호출하는 함수에 제네릭 유형을 전달하겠습니다.
Rocky Pulley

당신은 예와 정교한
Thirumal

31
if(!myList.isEmpty() && myList.get(0) instanceof MyType){
    // MyType object
}

6
... 그리고 빈 목록은? 반사?
Gewure

네. 이것이 빈 목록에 사용할 수있는 유일한 옵션입니다. stackoverflow.com/questions/1942644/…
Sathish

11
이 대답은 안전하지 않습니다. 0 요소가 MyType 인 경우에도 다른 요소는 다른 유형일 수 있기 때문입니다. 예를 들어 목록이 ArrayList <Object>로 선언 된 다음 MyType이 추가 된 다음 문자열이 추가되었을 수 있습니다.
Adam Gawne-Cain

@ AdamGawne-Cain 안전하지는 않지만 목록에 대해 많이 알지 못하는 사람들을위한 유일한 솔루션입니다. 예를 들어- value를 반환 하는 지역 변수 Object가 있으며 목록인지 확인해야합니다. 목록인지 여부, 내 인터페이스의 목록 유형 인스턴스인지 확인합니다. 여기서는 래퍼 나 매개 변수화 된 유형이 유용하지 않습니다.
SocketByte 2018

myList 는 어디에 선언됩니까?
IgorGanapolsky

9

확인할 유형을 얻으려면 리플렉션을 사용해야 할 것입니다. 목록 유형을 가져 오려면 다음을 수행하십시오. java.util.List의 일반 유형 가져 오기


2
내가 아는 한, 그것은 필드에서만 작동하지만 언급에는 +1입니다.
Tim Pote

6

비어 있지 않은의 object인스턴스 인지 확인하려는 경우 사용할 수 있습니다 List<T>.

if(object instanceof List){
    if(((List)object).size()>0 && (((List)object).get(0) instanceof MyObject)){
        // The object is of List<MyObject> and is not empty. Do something with it.
    }
}

2
    if (list instanceof List && ((List) list).stream()
                                             .noneMatch((o -> !(o instanceof MyType)))) {}

1

Object의 List 또는 Map 값의 참조가 Collection의 인스턴스인지 확인하는 경우 필요한 List의 인스턴스를 만들고 해당 클래스를 가져옵니다.

Set<Object> setOfIntegers = new HashSet(Arrays.asList(2, 4, 5));
assetThat(setOfIntegers).instanceOf(new ArrayList<Integer>().getClass());

Set<Object> setOfStrings = new HashSet(Arrays.asList("my", "name", "is"));
assetThat(setOfStrings).instanceOf(new ArrayList<String>().getClass());

당신의 요점 무엇 setOfIntegerssetOfStrings?
DanielM

@DanielM이 방금 샘플을 업데이트했습니다. 해당 참조를 사용해야합니다! 감사!
Marcello de Sales

1

이것이 제네릭 (@Martijn의 대답)으로 래핑 될 수 없다면 중복 목록 반복을 피하기 위해 캐스팅하지 않고 전달하는 것이 좋습니다 (첫 번째 요소의 유형을 확인해도 아무것도 보장하지 않음). 목록을 반복하는 코드에서 각 요소를 캐스팅 할 수 있습니다.

Object attVal = jsonMap.get("attName");
List<Object> ls = new ArrayList<>();
if (attVal instanceof List) {
    ls.addAll((List) attVal);
} else {
    ls.add(attVal);
}

// far, far away ;)
for (Object item : ls) {
    if (item instanceof String) {
        System.out.println(item);
    } else {
        throw new RuntimeException("Wrong class ("+item .getClass()+") of "+item );
    }
}

0

instanceof를 사용하는 대신 가짜 팩토리를 사용하여 많은 메서드를 포함 할 수 있습니다.

public class Message1 implements YourInterface {
   List<YourObject1> list;
   Message1(List<YourObject1> l) {
       list = l;
   }
}

public class Message2 implements YourInterface {
   List<YourObject2> list;
   Message2(List<YourObject2> l) {
       list = l;
   }
}

public class FactoryMessage {
    public static List<YourInterface> getMessage(List<YourObject1> list) {
        return (List<YourInterface>) new Message1(list);
    }
    public static List<YourInterface> getMessage(List<YourObject2> list) {
        return (List<YourInterface>) new Message2(list);
    }
}

0

여기서 주요 관심사는 컬렉션이 정의에서 유형을 유지하지 않는다는 것입니다. 유형은 런타임에서만 사용할 수 있습니다. 복잡한 컬렉션을 테스트하는 함수를 생각해 냈습니다 (하지만 하나의 제약이 있습니다).

객체가 일반 컬렉션의 인스턴스인지 확인합니다. 컬렉션을 나타 내기 위해

  • 수업 없음, 항상 false
  • 하나의 클래스는 컬렉션이 아니며 instanceof평가 결과를 반환합니다.
  • List또는 을 나타 내기 Set위해 목록의 유형이 다음으로 나옵니다. 예를 들어 {List, Integer} forList<Integer>
  • 를 나타 내기 Map위해 키 및 값 유형이 다음에 나옵니다. 예를 들어 {Map, String, Integer} forMap<String, Integer>

동일한 규칙을 사용하여 더 복잡한 사용 사례를 생성 할 수 있습니다. 예를 들어를 나타 내기 위해 다음 List<Map<String, GenericRecord>>과 같이 호출 할 수 있습니다.

    Map<String, Integer> map = new HashMap<>();
    map.put("S1", 1);
    map.put("S2", 2);
    List<Map<String, Integer> obj = new ArrayList<>();
    obj.add(map);
    isInstanceOfGenericCollection(obj, List.class, List.class, Map.class, String.class, GenericRecord.class);

이 구현은 Map에서 중첩 된 유형을 지원하지 않습니다. 따라서 키 및 값의 유형은 컬렉션이 아닌 클래스 여야합니다. 그러나 그것을 추가하는 것은 어렵지 않습니다.

    public static boolean isInstanceOfGenericCollection(Object object, Class<?>... classes) {
        if (classes.length == 0) return false;
        if (classes.length == 1) return classes[0].isInstance(object);
        if (classes[0].equals(List.class))
            return object instanceof List && ((List<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Set.class))
            return object instanceof Set && ((Set<?>) object).stream().allMatch(item -> isInstanceOfGenericCollection(item, Arrays.copyOfRange(classes, 1, classes.length)));
        if (classes[0].equals(Map.class))
            return object instanceof Map &&
                    ((Map<?, ?>) object).keySet().stream().allMatch(classes[classes.length - 2]::isInstance) &&
                    ((Map<?, ?>) object).values().stream().allMatch(classes[classes.length - 1]::isInstance);
        return false;
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.