2015-08-27 5 views
2

У меня есть List общих объектов типа MyClass<T>, из которых я не знаю точный тип: List<MyClass<? extends Object>>.Фильтрация Список общих объектов для одного типового экземпляра

Есть ли способ, чтобы отфильтровать этот список, чтобы получить только те объекты, которые имеют конкретный Tбез литья или с использованием instanceof?.

У меня есть чувство, что это может быть сделано с Visitor pattern и подклассов на конкретный экземпляр T (как MyClassString extends MyClass<String>, которая не является проблемой), но я не хочу, чтобы реализовать Visitor для каждого подкласса:

class MyClassString extends MyClass<String> { 

    public <U> U accept(MyClassVisitor<U> visitor) { 
     return visitor.visitMyClassString(this); 
    } 

} 

interface MyClassVisitor<U> { 

    U visitMyClassString(MyClassString myClassString); 
    U visitMyClassDouble(MyClassDouble myClassDouble); 
    ... 

} 

class FilterMyClassStringService implements MyClassVisitor<List<MyClassString>> { 

    public List<MyClassString> filterMyClassString(List<MyClass<? extends Object>> toFilter) { 
     List<MyClassString> filteredList = new ArrayList<>(); 
     for (MyClass<? extends Object> elem : toFilter) { 
      filteredList.addAll(elem.accept(this)); 
     } 
     return filteredList; 
    } 

    @Override 
    public List<MyClassString> visitMyClassString(MyClassString myClassString) { 
     List<MyClassString> listWithMyClassString = new ArrayList<>(); 
     listWithMyClassString.add(myClassString); 
     return listWithMyClassString; 
    } 

    @Override 
    public List<MyClassString> visitMyClassDouble(MyClassDouble myClassDouble) { 
     return new ArrayList<MyClassString>(); 
    } 

} 

Есть ли способ?

+0

Если вы используете Java 8, вы можете использовать поток для фильтрации. –

+1

не могли бы вы рассказать нам, почему вы не хотите использовать экземпляр? Это дорого? –

+0

Честно говоря, я просто хочу знать, можно ли это сделать. Одна из причин против использования 'instanceOf' во многих местах заключается в том, что легко забыть добавлять другой случай в каждый' if', который проверяет тип. Шаблон посетителя заставляет всех, кто вводит тип (используя посетителя), рассматривать новый тип, когда он добавляется в программу. –

ответ

1

Я думаю, что понимаю, что вы хотели бы иметь. И это возможно в некотором роде. Если применить обсуждение из этой темы (How to get the generic type at runtime?) в вашем случае, то мы будем иметь что-то вроде этого кода:

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

public class TypedReflectTest { 
    public static void main(String[] args) { 
     List<MyClass<?>> list = new ArrayList<MyClass<?>>(); 
     list.add(new MyClassInteger(123)); 
     list.add(new MyClassDouble(123.45)); 
     list.add(new MyClassString("1234")); 
     System.out.println(filterMyClass(list, Integer.class)); 
    } 

    public static List<MyClass<?>> filterMyClass(List<MyClass<?>> toFilter, Class<?> innerType) { 
     List<MyClass<?>> filteredList = new ArrayList<MyClass<?>>(); 
     for (MyClass<?> elem : toFilter) { 
      if (!elem.getInnerType().equals(innerType)) 
       continue; 
      filteredList.add(elem); 
     } 
     return filteredList; 
    } 
} 

abstract class MyClass<T> { 
    private T value; 
    private Class<?> innerType; 

    public MyClass(T value) { 
     this.value = value; 
     Type superClass = getClass().getGenericSuperclass(); 
     innerType = (Class<?>)(((ParameterizedType) superClass).getActualTypeArguments()[0]); 
    } 

    public T getValue() { 
     return value; 
    } 

    public Class<?> getInnerType() { 
     return innerType; 
    } 

    @Override 
    public String toString() { 
     return "MyClass(" + value + ")"; 
    } 
} 

class MyClassInteger extends MyClass<Integer> { 
    public MyClassInteger(Integer value) { 
     super(value); 
    } 
} 

class MyClassDouble extends MyClass<Double> { 
    public MyClassDouble(Double value) { 
     super(value); 
    } 
} 

class MyClassString extends MyClass<String> { 
    public MyClassString(String value) { 
     super(value); 
    } 
} 

Вы должны заметить, что абстрактный класс супер очень важно здесь. Вы не можете иметь дело с экземплярами самого типа MyClass. К сожалению, вы должны расширить этот класс, чтобы получить параметризованный тип во время выполнения.

Смежные вопросы