2016-06-28 2 views
1

Я писал код, где я пытался наложить объект на карту.Принудительное принуждение Список к карте не бросает ClassCastException или что такое ArrayList1_groovyProxy?

Map a = object as Map 

Я мог бы в качестве альтернативы использовать

Map a = (Map) object 

и весь вопрос был бы неуместным, поскольку это бросает ClassCastException если объект находится в списке типов, но с помощью бывшего я обнаружил интересную вещь. Если объект представляет собой Список, то есть object = [], принудительное принуждение типа будет отличаться от ожидаемого.

Мое предположение было получить ClassCastException, но вместо этого я получил результирующий объект. Но этот объект кажется странным. Это экземпляр списка и экземпляр карты, и с использованием .toString() на нем выводится вывод списка, а не карты ([a,b]). Также невозможно установить значение на карте с помощью a['c'] = 'c'. Это приводит к java.lang.IllegalArgumentException: argument type mismatch.

Map a = ['a', 'b'] as Map 

println(a) 
println(a instanceof List) 
println(a instanceof Map) 
println(a.getClass()) 

приводит следующий вывод:

[a, b] 
true 
true 
class ArrayList1_groovyProxy 

Я пытался Google, чтобы узнать, что это ArrayList1_groovyProxy есть, но не смог найти ничего.

Мне до сих пор не имеет смысла, что принуждение возвращает объект, который, очевидно, не является тем, чем он должен быть, и также выглядит как сломанный, а не просто бросает ClassCastException.

Может ли кто-нибудь объяснить мне причину такого поведения вместо того, чтобы выбрасывать исключение и объяснять использование ArrayList1_groovyProxy? Или это просто ошибка в groovy?

+0

'['a', 'b']' является 'List'. Если вам нужна карта, то определите 'def map = ['1': 'one', '2': 'two']'. Теперь попробуйте 'assert map instanceof Map' – Rao

+0

Я знаю, что' ['a', 'b'] '- это List. Дело не в этом. Вопросы были связаны с тем, что '['a', 'b'] как Map' не генерирует ClassCastException, например' (Map) ['a', 'b'] '. Потому что кажется, что результирующий объект довольно непригоден. – alexanderfranke

+0

Не уверен, но вы заставляете его указывать «как карту» при определении. Вы можете увидеть исключение с помощью 'Map a = ['a', 'b']' – Rao

ответ

2

asoperator вызывает метод asType с предоставленным типом в качестве аргумента метода.

Вы можете увидеть реализацию по умолчанию для asType в DefaultGroovyMethods.

С Map это интерфейс, он в конечном итоге вызовет ProxyGenerator.INSTANCE.instantiateDelegate(interfaces, obj), который возвращает динамический прокси-сервер, который реализует Map.

/** 
* Converts a given object to a type. This method is used through 
* the "as" operator and is overloadable as any other operator. 
* 
* @param obj the object to convert 
* @param type the goal type 
* @return the resulting object 
* @since 1.0 
*/ 
@SuppressWarnings("unchecked") 
public static <T> T asType(Object obj, Class<T> type) { 
    if (String.class == type) { 
     return (T) InvokerHelper.toString(obj); 
    } 

    // fall back to cast 
    try { 
     return (T) DefaultTypeTransformation.castToType(obj, type); 
    } 
    catch (GroovyCastException e) { 
     MetaClass mc = InvokerHelper.getMetaClass(obj); 
     if (mc instanceof ExpandoMetaClass) { 
      ExpandoMetaClass emc = (ExpandoMetaClass) mc; 
      Object mixedIn = emc.castToMixedType(obj, type); 
      if (mixedIn != null) 
       return (T) mixedIn; 
     } 
     if (type.isInterface()) { 
      try { 
       List<Class> interfaces = new ArrayList<Class>(); 
       interfaces.add(type); 
       return (T) ProxyGenerator.INSTANCE.instantiateDelegate(interfaces, obj); 
      } catch (GroovyRuntimeException cause) { 
       // ignore 
      } 
     } 
     throw e; 
    } 

Как почему Groovy идет на такие большие длины, чтобы принуждать типов - это в основном природа Groovy: создание Java кодирования проще. Вы можете построить объект по passing a Map to its constructor или даже coerce a Map instance to a particular type; так почему бы не позволить каждому объекту вернуться в Map с помощью оператора as?

+0

Большое спасибо. Это объясняет прокси-класс. Все еще не объясняет, почему он даже вернет это, если он тогда не поддерживает обычные операции с Картой. Я согласен с тем, что все в порядке, чтобы вернуть все обратно на карту, если карта может использоваться в конструкторах для создания всего, но не ожидалось ли тогда ожидание только что-то вроде object.properties? – alexanderfranke

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