2013-04-02 3 views
0

Мое приложение бросаетПолучить общее название класса типа во время выполнения

java.lang.ClassCastException: java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 

Для этого кода:

public class DsMap<K,V> implements Map<K, V>{ 
    protected Class<K> kClazz; 
    protected Class<V> vClazz; 

    // Called during DS.getMap(mapName) method 
    public DsMap(String name) { 
     ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); 
     Type typeK = genericSuperclass.getActualTypeArguments()[0]; 
     Type typeV = genericSuperclass.getActualTypeArguments()[1]; 

     if (typeK instanceof Class) { 
      this.kClazz = (Class<K>) typeK; 
     } else if (typeK instanceof ParameterizedType) { 
      this.kClazz = (Class<K>) ((ParameterizedType)typeK).getRawType(); 
     } 

     if (typeV instanceof Class) { 
      this.vClazz = (Class<V>) typeV; 
     } else if (typeV instanceof ParameterizedType) { 
      this.vClazz = (Class<V>) ((ParameterizedType)typeV).getRawType(); 
     }   
    } 
} 

То, что я пытаюсь добиться, чтобы получить имя класса K и V во время выполнения:

Такое, что делает это:

Map<String,String> dsMap = DS.getMap(mapName); 

я доберусь java.lang.String для имен классов kClazz и vClazz, или получить то, что имя класса параметрироваться (без инстанцирования Class<K> и Class<V>)

Что может быть не так в моем коде?

+0

При таком подходе к работе, вы должны сделать 'DsMap' абстрактным и создать его экземпляр с реальными типами, например, 'new DsMap () {}'. –

+0

Возможно, вам будет полезно посмотреть документацию и реализацию ['TypeToken' в Гуаве] (http://docs.guava-libraries.googlecode.com/git-history/release/javadoc/com/google/common/ отражают/TypeToken.html). –

ответ

0

DsMap реализует общий интерфейс (Map<K,V>), но он не распространяется на общий класс. Таким образом, getClass().getGenericSuperclass() возвращает ссылку на java.lang.Object, которая не может быть отлита до ParameterizedType.

(ParameterizedType) getClass().getGenericSuperclass() трюк применяется только тогда, когда 1) Подкласс расширяет общий класс 2) Подкласс декларирует свои аргументы типа во время компиляции

например:

public abstract class DsMap<K, V> implements Map<K, V> { 

...

public class StringIntDsMap extends DsMap<String, Integer> { 

...

Затем getGenericSuperclass() вернет DsMap, который может быть отлит до ParameterizedType, а записи в массиве Type[], возвращенные с getActualTypeArguments(), могут быть отлиты до Class.

К сожалению, это не очень распространенное состояние. Я часто использовал его для совместного использования кода между модульными тестами (где я могу объявлять общие типы во время компиляции). Но это не обобщает случай, когда типы недоступны до времени выполнения.

1

Параметрированный тип представляет собой бетон реализация общего типа. Вы можете думать о взаимосвязи между типичным и параметризованным типом так же, как вы думаете об отношениях между шаблоном и документом . Шаблон говорит вам, где бы вы заполнить информацию, документ содержит информацию, на самом деле заполнены в вашем примере:.

public class DsMap<K,V> implements Map<K, V> 

Оба DsMap и Map родовые типы (или шаблоны). Их фактические общие параметры не определяются самим классом и как таковые не записываются компилятором. Другими словами, их общая информация недоступна во время выполнения.

Чтобы зафиксировать фактические общие параметры во время выполнения, эти параметры должны быть частью подписи класса. Например, это простое расширение вашего класса будет работать:

public class DsMapIntegerString extends DsMap<Integer, String> 

Поскольку вы указали конкретные параметры, тип, возвращаемый getClass().getGenericSuperclass() на самом деле будет параметризованный класс, и ваш код больше не будет терпеть неудачу.

0

Визуальный осмотр говорит попытаться изменить:

static public class DsMap<K, V> implements Map<K, V> { 

Для

static public class DsMap<K, V> extends HashMap<K, V> {