2017-01-15 3 views
1

У меня есть класс с различными конструкторами:Java дженериков: Как определить точный метод подписи

public class SomeClass { 

    public SomeClass(Object obj) { 
     Log.d("x", "SomeClass(Object)"); 
    } 

    public SomeClass(Integer num) { 
     Log.d("x", "SomeClass(Integer)"); 
    } 

    public SomeClass(String str) { 
     Log.d("x", "SomeClass(String)"); 
    } 

    public <K, V> SomeClass(Map<K, V> map) { 
     Log.d("x", "SomeClass(List)"); 
     for (K key : map.keySet()) { 
      new SomeClass(key); 
      new SomeClass(map.get(key)); 
     } 
    } 
} 

... и некоторый код, который использует его следующим образом:

HashMap<String, Integer> map = new HashMap<>(); 
map.put("key", 100); 
new SomeClass(map); 

В результате у меня есть такой вывод:

"SomeClass(List)" 
"SomeClass(Object)" 
"SomeClass(Object)" 

вместо необходимости

"SomeClass(List)" 
"SomeClass(String)" 
"SomeClass(Integer)" 

Я полагаю, что из-за Java Type Erasure вложенные вызовы конструкторов SomeClass попадают в самый общий.

Вопрос: любые идеи, как преодолеть это поведение Java и заставить его вызвать конструктор с требуемым типом параметра? (Статические обертки и шаблон ткани здесь не принимаются)

+0

Вы только с помощью этого класса с 'Map ' или также отображает с другими типами? –

+0

Помимо проверки типа ключа и значения с помощью instanceof, я не вижу никакого * принятого * способа. Я думаю, что дизайн должен быть изменен, но вы, кажется, отклоняете этот параметр, поэтому ... Например, я не понимаю, как сделать параметризацию конструктора. Вы можете использовать карту . –

+1

Java использует статический тип для разрешения метода, в случае дженериков это стирание здесь «Объект». Помимо ручного литья по назначению или с использованием рефлекса ваши варианты с конструкторами ограничены. Вы можете изменить подпись конструктора на 'SomeClass (Map map)'. Но более общее решение - исправить ваш дизайн. –

ответ

2

Перегрузка выполняется во время компиляции и поэтому использует статический тип переменной, а не тип времени выполнения. Это не имеет ничего общего с дженериками.

Рассмотрим код:

Object value = "value"; 
SomeClass something = new SomeClass(value); 

Затем используется перегрузка SomeClass(Object).

Вы можете использовать instanceof, но это, как правило, хороший признак того, что в дизайне что-то не так. Почти наверняка вы хотите, чтобы у Map был соответствующий тип. На данный момент вы могли бы написать последний конструктор, как: (. Кстати, общие конструкторы действительно неясными)

public SomeClass(Map<?, ?> map) { 

+0

Насколько я понимаю, вы предлагаете вставить большой {if-elseif-elseif -...- else } с условием «instanceof» вообще конструктором SomeClass (Object value). Раньше у меня было такое решение, оно работает так, как ожидалось.Теперь я пытаюсь найти лучшее решение и избежать этого уродливого кода ... –

+0

@SergeyKrivenkov Проблема не в том, что 'instanceof' является уродливым, но что дизайн основан на идентификации типов времени выполнения. –

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