나는 가지고있다;
List<String> stringList = new ArrayList<String>();
List<Integer> integerList = new ArrayList<Integer>();
목록의 일반 유형을 검색하는 쉬운 방법이 있습니까?
나는 가지고있다;
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.
}
}
매개 변수 유형 및 리턴 유형 메소드에 대해서도이를 수행 할 수 있습니다.
그러나 그들이 당신이 그들에 대해 알아야 할 클래스 / 방법의 동일한 범위 내에 있다면, 당신이 이미 스스로 선언했기 때문에 그것을 알 필요가 없습니다.
<?>
대신 (와일드 카드 유형)을 사용하고 <Class>
있습니다. <?>
로 <Class>
또는 무엇이든 교체하십시오 <E>
.
메소드 매개 변수에 대해서도 동일한 작업을 수행 할 수 있습니다.
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에 의해 제한된다는 사실 만 포함하지만 그 이상으로 말할 방법이 없습니다.
List<Integer>
and 로 명시 적으로 선언 하고있다 List<String>
; 이 경우 유형 삭제가 적용되지 않습니다.
컬렉션의 제네릭 형식은 실제로 개체가 들어있는 경우에만 중요합니다. 따라서 수행하기가 쉽지 않습니다.
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());
}
Object
s 모음으로 선언 하고 목록에서 가져올 때 유형에 따라 적절한 처리기에 제공합니다.
제네릭 형식의 반환 형식을 가져와야하는 경우 클래스에서 메서드를 찾아서 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);
}
}
런타임시에는 불가능합니다.
그러나 리플렉션을 통해 유형 매개 변수 에 액세스 할 수 있습니다. 시험
for(Field field : this.getDeclaredFields()) {
System.out.println(field.getGenericType())
}
이 메소드 getGenericType()
는 Type 객체를 반환합니다. 이 경우,의 인스턴스가되며,이 경우 ParametrizedType
메소드 getRawType()
( List.class
이 경우 에는 포함 )와 getActualTypeArguments()
배열 (이 경우에는 길이가 1 String.class
또는 하나 포함 Integer.class
) 을 리턴합니다 .
method.getGenericParameterTypes()
선언 된 메소드 매개 변수 유형을 가져 오는 데 사용할 수 있습니다 .
같은 문제가 있었지만 대신 instanceof를 사용했습니다. 이런 식으로 했습니까?
List<Object> listCheck = (List<Object>)(Object) stringList;
if (!listCheck.isEmpty()) {
if (listCheck.get(0) instanceof String) {
System.out.println("List type is String");
}
if (listCheck.get(0) instanceof Integer) {
System.out.println("List type is Integer");
}
}
}
여기에는 검사되지 않은 캐스트 사용이 포함되므로 목록임을 알 수 있고 유형이 무엇인지 알 때만 수행하십시오.
다른 사람들이 말했듯이, 유일한 정답은 아니오입니다. 유형이 지워졌습니다.
리스트에 0이 아닌 요소가있는 경우 첫 번째 요소의 유형을 조사 할 수 있습니다 (예 : getClass 메소드 사용). 그것은 당신에게리스트의 제네릭 타입을 말하지는 않지만 제네릭 타입이리스트에있는 타입의 수퍼 클래스라고 가정하는 것이 합리적입니다.
나는 접근 방식을 옹호하지는 않지만 바인드에서는 유용 할 수 있습니다.
List<Integer>
and 로 명시 적으로 선언 하고있다 List<String>
; 이 경우 유형 삭제가 적용되지 않습니다.
import org.junit.Assert;
import org.junit.Test;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class GenericTypeOfCollectionTest {
public class FormBean {
}
public class MyClazz {
private List<FormBean> list = new ArrayList<FormBean>();
}
@Test
public void testName() throws Exception {
Field[] fields = MyClazz.class.getFields();
for (Field field : fields) {
//1. Check if field is of Collection Type
if (Collection.class.isAssignableFrom(field.getType())) {
//2. Get Generic type of your field
Class fieldGenericType = getFieldGenericType(field);
//3. Compare with <FromBean>
Assert.assertTrue("List<FormBean>",
FormBean.class.isAssignableFrom(fieldGenericType));
}
}
}
//Returns generic type of any field
public Class getFieldGenericType(Field field) {
if (ParameterizedType.class.isAssignableFrom(field.getGenericType().getClass())) {
ParameterizedType genericType =
(ParameterizedType) field.getGenericType();
return ((Class)
(genericType.getActualTypeArguments()[0])).getSuperclass();
}
//Returns dummy Boolean Class to compare with ValueObject & FormBean
return new Boolean(false).getClass();
}
}
getFieldGenericTypefieldGenericType
그것을 찾을 수 없습니다
유형이 지워져 사용할 수 없습니다. http://en.wikipedia.org/wiki/Type_erasure 및 http://en.wikipedia.org/wiki/Generics_in_Java#Type_erasure를 참조하십시오 .
List<Integer>
and 로 명시 적으로 선언 하고있다 List<String>
; 이 경우 유형 삭제가 적용되지 않습니다.
Reflection을 사용 Field
하여 이것들 을 얻으면 다음과 같이 할 수 있습니다 : field.genericType
generic에 대한 정보가 들어있는 유형을 얻으려면.