2017-01-29 2 views
1

Это то, на чем я столкнулся, пытаясь решить чужой вопрос здесь, в упрощенной версии. Клиент и сервер с рефлексивной (циклической) зависимостью используют общие методы, чтобы попытаться сохранить строго типизированные ссылки в суперклассе. Желание было для произвольных подтипов подтипа, таких как ClientType1 < -> ServerType2, а для строго типизированных вызовов по специализированным методам, найденным только в определенном типе.Классы дженериков с рефлексивной зависимостью

Это работает только на одном уровне глубины: от сервера к клиенту, но не удается, если вы затем попытаетесь продолжить с этого клиента обратно на сервер: Есть ли какой-либо синтаксис, который бы разрешал произвольные уровни строго типизированных вызовов?

abstract class ServerBase<C extends ClientBase<?>> 
{ 
    ArrayList<C> clients = new ArrayList<C>(); 
} 
abstract class ClientBase<S extends ServerBase<?>> 
{ 
    S server; 
} 
class ClientType1<S extends ServerBase<?>> extends ClientBase<S> 
{ 
    public void clientType1Method() {} 
} 

class ServerType1<C extends ClientBase<?>> extends ServerBase<C> 
{ 

} 



public class Example { 
    public static void main(String[] args) { 
     ServerType1<ClientType1<?>> s = new ServerType1<>(); 
     s.clients.get(0).clientType1Method(); // Single depth level - OK 
     s.clients.get(0).server.clients.get(0).clientType1Method(); // level 2 - compiler error - undefined method  
    } 
} 

ответ

2

По-моему, на самом деле вам не нужна такая сложная ссылка.

Что вы на самом деле имеете в виду, так это то, что клиент должен хранить ссылку на сервер, к которому он может подключиться, и наоборот.

должен работать это:

abstract class ServerBase<C extends ClientBase<? extends ServerBase>> 
{ 
    ArrayList<C> clients = new ArrayList<C>(); 
} 
abstract class ClientBase<S extends ServerBase<? extends ClientBase>> 
{ 
    S server; 
} 
1

Если вы делаете небольшую настройку с этим кодом, безусловно, работать.

abstract class ClientBase<S extends ServerBase<?>> { 
    S server; 

    public abstract void clientMethod(); 
} 

.......

public static void main(String[] args) { 
    ServerType1<ClientBase<?>> s = new ServerType1<>(); 
    s.clients.get(0).clientMethod(); // Single depth level - OK 

    s.clients.get(0).server.clients.get(0).clientMethod(); 
    // second level - NO compiler error 
} 
+0

Спасибо, хотя это и не было смысла. Он должен работать на произвольных уровнях, и clientMethod должен быть уникальным в каждом производном классе (например, другое имя или подпись) –

0

Ну, это не удается, потому что вы вошли Самостоятельно ? вместо фактического типа. Если вы используете

ServerType1<ClientType1<ServerType1<ClientType1<?>>>> s = new ServerType1<>(); 
s.clients.get(0).clientType1Method(); 
s.clients.get(0).server.clients.get(0).clientType1Method(); 

вместо этого он будет работать. Хотя это совершенно бессмысленно, если предположить, что s.clients.get(0).server совпадает с s.

Работа с циклической зависимостью, только если вы назвали типы, на которые вы можете ссылаться, например.

public static <S extends ServerType1<ClientType1<S>>> void main(String[] args) { 
    ServerType1<ClientType1<S>> s = new ServerType1<>(); 
    s.clients.get(0).clientType1Method(); 
    s.clients.get(0).server.clients.get(0).clientType1Method(); 
    s.clients.get(0).server.clients.get(0).server.clients.get(0).clientType1Method(); 
    s.clients.get(0).server.clients.get(0).server.clients.get(0) 
        .server.clients.get(0).clientType1Method(); 
    s.clients.get(0).server.clients.get(0).server.clients.get(0) 
        .server.clients.get(0).server.clients.get(0).clientType1Method(); 
} 

Хотя это, скорее всего, нецелесообразно для большинства случаев использования. Как только вам придется создать экземпляр S, вам понадобится реальный класс. Вы должны переосмыслить, действительно ли вам нужна такая общая конструкция. И если вы действительно рассматриваете создание такого кода с переменными вспомогательного типа, которые не имеют отношения к вызывающему методу, вы должны сделать это с помощью методов private, чтобы избежать их видимости в API public вашего класса.

+0

Почему вы так думаете? Он работает правильно. – Holger

+0

Не компилируется. –

+0

Ну, это с моим jdk. Если вы получаете ошибку компиляции, вы должны опубликовать эту ошибку или даже лучше попытаться понять код (это цель публикации кода в ответе на ваш вопрос) и сказать мне, что с ним не так. – Holger

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