2015-04-30 2 views
4

У меня возникли проблемы с заводским шаблоном при использовании дженериков. У меня есть этот интерфейс, общий на все:Завод по производству генераторов Java

public interface Connection<T> { 
    /* methods */ 
} 

Очевидно, что у меня есть эта реализация:

public class ImplConnection<V> implements Connection<V> { 
    /* body */ 
} 

Тогда у меня есть этот завод, который должен создать экземпляр связи:

public class ConnectionFactory<V, C extends Connection<V>> { 
    private final Class<V> contentType; 
    private final Class<C> connectionType; 

    public ConnectionFactory(Class<V> contentType, Class<C> connectionType) { 
     this.contentType = contentType; 
     this.connectionType = connectionType; 
    } 

    public C newConnection() { 
     try { 
      return connectionType.newInstance(); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

Я пытаюсь создать экземпляр соединения во время выполнения с помощью этого (я использую Integer в качестве параметра для общего типа):

connectionFactory = new ConnectionFactory<Integer, Connection<Integer>>(Integer.class, Connection.class); 

, но он говорит:

The constructor ConnectionFactory <Integer,Connection<Integer>>(Class<Integer>, Class<Connection>) is undefined. 
+0

Это классическая проблема Java. Ваш конструктор запросит «Класс », но вам нужен «Класс <Соединение >». К несчастью, вы не можете иметь такую ​​вещь для стирания типов дженериков. –

+0

Вы, вероятно, не хотите передавать 'Connection.class', так как это интерфейс, и вам нужно создать экземпляр данного класса connectionType. Полагаю, вы на самом деле выберете класс во время выполнения, используя отражение, не так ли? Как вы его загружаете? –

ответ

4

При передаче параметров класса, Connection не распространяется Connection<Integer>. Таким образом, Class<Connection> не может быть задан как параметр Class<? extends Connection<Integer>>. Это то, что скрывается за вашей ошибкой.

Что вы должны сделать, если вы хотите сохранить этот вид шаблона должен иметь somehting так:

public class IntegerConnection implements Connection<Integer> {} 

Это будет работать.

Однако, и вообще, вы знаете, что вы можете создать общий экземпляр, не набирая ничего особенного?

public class ConnectionFactory { 
    public <T> Connection<T> newConnection() { 
    return new ConnectionImpl<T>(); 
    } 
} 

И вы можете использовать его как это:

Connection<Integer> connection = connectionFactory.newInstance(); 
+0

Вы можете очень переходить в 'Connection' на' C extends Connection' ... – chancea

+1

Да, вы можете, но не 'Class ' '' классу > '. –

+0

Хорошо, что имеет смысл, возможно, вы могли бы уточнить, что – chancea

1

Когда я работаю с генериков я часто использую Guava TypeToken. Они очень полезны. Ваш класс может быть таким:

public class ConnectionFactory<V, C extends Connection<V>> { 
    private final TypeToken<V> contentType; 
    private final TypeToken<C> connectionType; 

    public ConnectionFactory() { 
     this.contentType = new TypeToken<V>(getClass()) {}; 
     this.connectionType = new TypeToken<C>(getClass()) {}; 
    } 

    public C newConnection() { 
     try { 
      return (C) connectionType.getRawType().newInstance(); 
     } catch (Exception e) { 
      throw new RuntimeException(e); 
     } 
    } 
} 

Постарайтесь.

+0

'ConnectionFactory' необходимо создать таким образом:' new ConnectionFactory >() {} ', правильно? – Radiodef

+0

'TypeToken' не имеет никакого метода' newInstance() '. –

+0

@ OlivierGrégoire правый! – davioooh

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