[java] java.util.List의 일반 유형을 가져옵니다.

나는 가지고있다;

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

목록의 일반 유형을 검색하는 쉬운 방법이 있습니까?



답변

이들이 실제로 특정 클래스의 필드라면 약간의 반성으로 필드를 얻을 수 있습니다.

package test;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;

public class Test {

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

    public static void main(String... args) throws Exception {
        Field stringListField = Test.class.getDeclaredField("stringList");
        ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
        Class<?> stringListClass = (Class<?>) stringListType.getActualTypeArguments()[0];
        System.out.println(stringListClass); // class java.lang.String.

        Field integerListField = Test.class.getDeclaredField("integerList");
        ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
        Class<?> integerListClass = (Class<?>) integerListType.getActualTypeArguments()[0];
        System.out.println(integerListClass); // class java.lang.Integer.
    }
}

매개 변수 유형 및 리턴 유형 메소드에 대해서도이를 수행 할 수 있습니다.

그러나 그들이 당신이 그들에 대해 알아야 할 클래스 / 방법의 동일한 범위 내에 있다면, 당신이 이미 스스로 선언했기 때문에 그것을 알 필요가 없습니다.


답변

메소드 매개 변수에 대해서도 동일한 작업을 수행 할 수 있습니다.

Type[] types = method.getGenericParameterTypes();
//Now assuming that the first parameter to the method is of type List<Integer>
ParameterizedType pType = (ParameterizedType) types[0];
Class<?> clazz = (Class<?>) pType.getActualTypeArguments()[0];
System.out.println(clazz); //prints out java.lang.Integer


답변

짧은 대답 : 아닙니다.

이것은 아마도 중복 일 것입니다. 지금은 적절한 것을 찾을 수 없습니다.

Java는 유형 삭제라는 것을 사용합니다. 즉, 런타임시 두 객체가 동일합니다. 컴파일러는 목록에 정수 또는 문자열이 포함되어 있으므로 형식이 안전한 환경을 유지할 수 있다는 것을 알고 있습니다. 이 정보는 런타임에 (객체 인스턴스별로) 손실되며 목록에는 ‘개체’만 포함됩니다.

클래스에 대해 조금, 매개 변수화 할 수있는 유형을 알 수 있지만 일반적으로 이것은 “Object”를 확장하는 것, 즉 무엇이든입니다. 유형을 다음과 같이 정의하면

class <A extends MyClass> AClass {....}

AClass.class는 매개 변수 A가 MyClass에 의해 제한된다는 사실 만 포함하지만 그 이상으로 말할 방법이 없습니다.


답변

컬렉션의 제네릭 형식은 실제로 개체가 들어있는 경우에만 중요합니다. 따라서 수행하기가 쉽지 않습니다.

Collection<?> myCollection = getUnknownCollectionFromSomewhere();
Class genericClass = null;
Iterator it = myCollection.iterator();
if (it.hasNext()){
    genericClass = it.next().getClass();
}
if (genericClass != null) { //do whatever we needed to know the type for

런타임에는 제네릭 형식과 같은 것이 없지만 런타임에 내부의 객체는 선언 된 제네릭과 동일한 형식이어야하므로 처리하기 전에 항목의 클래스를 테스트하기 만하면됩니다.

당신이 할 수있는 또 다른 일은 단순히 목록을 처리하여 올바른 유형의 멤버를 얻거나 다른 사람들을 무시하거나 다르게 처리하는 것입니다.

Map<Class<?>, List<Object>> classObjectMap = myCollection.stream()
    .filter(Objects::nonNull)
    .collect(Collectors.groupingBy(Object::getClass));

// Process the list of the correct class, and/or handle objects of incorrect
// class (throw exceptions, etc). You may need to group subclasses by
// filtering the keys. For instance:

List<Number> numbers = classObjectMap.entrySet().stream()
        .filter(e->Number.class.isAssignableFrom(e.getKey()))
        .flatMap(e->e.getValue().stream())
        .map(Number.class::cast)
        .collect(Collectors.toList());

그러면 클래스가 서브 클래스 인 모든 항목의 목록이 표시되며 필요한 항목 Number을 처리 할 수 ​​있습니다. 나머지 항목은 다른 목록으로 필터링되었습니다. 이들이 맵에 있으므로 원하는대로 처리하거나 무시할 수 있습니다.

다른 클래스의 항목을 모두 무시하려면 훨씬 간단 해집니다.

List<Number> numbers = myCollection.stream()
    .filter(Number.class::isInstance)
    .map(Number.class::cast)
    .collect(Collectors.toList());

목록에 특정 클래스와 일치하는 항목 만 포함되도록 유틸리티 메소드를 작성할 수도 있습니다.

public <V> List<V> getTypeSafeItemList(Collection<Object> input, Class<V> cls) {
    return input.stream()
            .filter(cls::isInstance)
            .map(cls::cast)
            .collect(Collectors.toList());
}


답변

한 필드의 일반 유형을 찾는 경우 :

((Class)((ParameterizedType)field.getGenericType()).getActualTypeArguments()[0]).getSimpleName()


답변

제네릭 형식의 반환 형식을 가져와야하는 경우 클래스에서 메서드를 찾아서 Collection제네릭 형식에 액세스해야 할 때이 방법 을 사용했습니다.

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;

public class Test {

    public List<String> test() {
        return null;
    }

    public static void main(String[] args) throws Exception {

        for (Method method : Test.class.getMethods()) {
            Class returnClass = method.getReturnType();
            if (Collection.class.isAssignableFrom(returnClass)) {
                Type returnType = method.getGenericReturnType();
                if (returnType instanceof ParameterizedType) {
                    ParameterizedType paramType = (ParameterizedType) returnType;
                    Type[] argTypes = paramType.getActualTypeArguments();
                    if (argTypes.length > 0) {
                        System.out.println("Generic type is " + argTypes[0]);
                    }
                }
            }
        }

    }

}

출력 :

제네릭 형식은 클래스 java.lang.String입니다.


답변

Steve K의 답변을 확장 :

/**
* Performs a forced cast.
* Returns null if the collection type does not match the items in the list.
* @param data The list to cast.
* @param listType The type of list to cast to.
*/
static <T> List<? super T> castListSafe(List<?> data, Class<T> listType){
    List<T> retval = null;
    //This test could be skipped if you trust the callers, but it wouldn't be safe then.
    if(data!=null && !data.isEmpty() && listType.isInstance(data.iterator().next().getClass())) {
        @SuppressWarnings("unchecked")//It's OK, we know List<T> contains the expected type.
        List<T> foo = (List<T>)data;
        return retval;
    }
    return retval;
}
Usage:

protected WhateverClass add(List<?> data) {//For fluant useage
    if(data==null) || data.isEmpty(){
       throw new IllegalArgumentException("add() " + data==null?"null":"empty"
       + " collection");
    }
    Class<?> colType = data.iterator().next().getClass();//Something
    aMethod(castListSafe(data, colType));
}

aMethod(List<Foo> foo){
   for(Foo foo: List){
      System.out.println(Foo);
   }
}

aMethod(List<Bar> bar){
   for(Bar bar: List){
      System.out.println(Bar);
   }
}