реализовать accept(SocketImpl s) и копирование объектов

Я реализую транспортный протокол Positive Acknowledgment and Retransmission с точки зрения сокетов RAW, и в таких случаях необходим подкласс SocketImpl. При реализации acceptmethod мне нужно что-то вроде этого:

protected void accept(SocketImpl s) {
    ...
    s.copy(socket);
}

где socket – это уже вычисленный объект SocketImpl, который необходимо скопировать в уже инициализированный объект SocketImpl s. . Я знаю, что существует Object clone(), но он возвращает новый объект, и мне нужно изменить s.

Кстати, некоторые из вас думают, что изменение параметра, в данном случае s, является неправильным дизайном. Это не единственный пример в стандартных библиотеках Java. implAccept(Socket s) класса ServerSocket — еще один пример. Но именно так это спроектировали инженеры Sun/Oracle. Я хотел бы знать, почему это такой плохой дизайн

На первый взгляд может показаться, что есть смысл предусмотреть общее мелкое target.copy(source), где target = souce.clone() будет эквивалентно target = new TheClass(); target.copy(source); но поскольку его не существует (возможно, по уважительной причине, пожалуйста, объясните), единственный выход — запрограммировать собственный метод копирования полей.

Я прав? Спасибо.


person francesc    schedule 25.10.2012    source источник
comment
Каково ваше окончательное намерение? Расширение SocketImpl (или любого другого сокета, если на то пошло) довольно необычная вещь.   -  person Victor Sorokin    schedule 26.10.2012
comment
@Victor: хотя название не предполагает этого, SocketImpl является абстрактным. Так что расширение должно быть одним из самых обычных способов его использования;)   -  person DaveFar    schedule 26.10.2012
comment
@DaveBall да, но все 3 класса, которые расширяют его в JDK 1.6.33, являются внутренними для JDK, и 2 из них имеют собственные методы (это означает, что они по сути являются частью реализации JDK и не предназначены для непосредственного расширения программистом приложения). И переход к сокету clone или copy — это не то, что вы должны делать в Java. Для таких вещей есть ядро ​​ОС.   -  person Victor Sorokin    schedule 26.10.2012
comment
@Victor: к вашему сведению, я реализую транспортный протокол с точки зрения необработанных IP-сокетов, поэтому подкласс SocketImpl является обязательным.   -  person francesc    schedule 26.10.2012


Ответы (2)


Вы неправильно поняли, для чего этот метод и как он работает. Я делал это много раз. SocketImpl, предоставленный implAccept(), предназначен для вновь принятого сокета, а не ServerSocket. Так что вам не нужна вторая копия. Все, что вам нужно сделать, это обернуть этот SocketImpl в Socket или ваш собственный производный класс Socket. Как ни странно, для этой цели предусмотрен даже конструктор Socket.

person user207421    schedule 25.10.2012
comment
Возможно, я не понимаю, но... Я пытаюсь внедрить образовательный протокол Positive Ack & Retransmission с точки зрения сокетов RAW, поэтому расширение SocketImpl обязательно. В основном accept --звонки--› implAccept --звонки--› getImpl().accept(SocketImpl s). Это тот, который я переопределяю. s — это уже созданный объект, поэтому у меня нет другого пути, кроме как изменить его. Пожалуйста, как всегда, просветите меня, если я ошибаюсь. - person francesc; 26.10.2012
comment
@francesc, вы не сможете осмысленно переопределить accept SocketImpl, если не используете JNI. Но если вы собираетесь использовать JNI, нет необходимости расширять класс JDK. Похоже, что люди используют java-библиотеку rockaw для сырых сокетов в java, см. stackoverflow.com/q/3854961/162634 - person Victor Sorokin; 26.10.2012
comment
@Victor: очевидно, я использую JNI и гораздо более простой интерфейс необработанных сокетов, чем каменная пила, в образовательных целях. - person francesc; 26.10.2012
comment
@francesc, тогда извините за белый шум с моей стороны, однако для будущих ответчиков было бы полезно, если бы вы могли обновить свой вопрос с помощью этой информации. - person Victor Sorokin; 26.10.2012

Я предполагаю, что стандартного target.copy(source) (т.е. метода изменяемого копирования) не существует, так как он нужен гораздо реже, чем клонирование:

  • вам нужно решить (для вашей ситуации и для всех ваших полей) индивидуально, должны ли они быть скопированы или идентичны (точно так же, как клонирование против глубокого клонирования);
  • обычно вы можете сделать дизайн таким, что вы просто переключаете ссылку, которую вы держите снаружи, поэтому в вашем случае вы можете просто переключиться на использование ссылки s вместо текущего объекта везде, что проще и намного эффективнее. Если вам нужны скопированные значения, это соответствует клонированию (или использованию конструктора копирования);
  • вы можете легко реализовать его, обернув параметр (объект s в вашем случае).

Последний пункт также отвечает на ваш второй вопрос: в качестве альтернативы копированию поля за полем вы можете реализовать класс пересылки, который перенаправляет все экспортированные методы SocketImpl в обернутое ядро ​​SocketImpl:

  • используйте ваш текущий класс реализации C как частную реализацию с protected void accept(SocketImpl s), просто выбрасывая исключение;
  • write a forwarding class D that
    • wraps a SocketImpl (e.g. an object of C), held in private field wrapped
    • расширяет SocketImpl и перенаправляет все свои методы, кроме accept в wrapped
    • реализует protected void accept(SocketImpl s) просто с { s.wrapped = this; }
  • если вы хотите, чтобы все поля копировались в определенных ситуациях, укажите accept скопированный параметр, например. через accept(s.clone()) (или клонировать в accept, если вам нужны копии во всех ситуациях);
  • выдавать только объекты типа D, так что исключение в C никогда не выдается.

¹ Эта реализация accept работает только для параметров типа D. В противном случае этот ужасный дизайн (с необходимостью видоизменять SocketImpl, указанный в качестве параметра) требует accept использования уродливых методов, таких как отражение (см., например, org.apache.harmony.luni.net.PlainSocketImpl по адресу http://www.docjar.com/html/api/org/apache/harmony/luni/net/PlainSocketImpl.java.html).

person DaveFar    schedule 25.10.2012
comment
Во-первых, точно так же, как есть clone с семантикой поверхностного копирования, мы вполне могли бы иметь стандартный target.copy(source), который копировал бы исходный код в цель. Во-вторых, я не свободен в выборе дизайна, который хочу. В accept(SocketImpl s) s находится уже созданный объект (см. мой ответ на @EJP), и мне нужно его изменить. - person francesc; 26.10.2012
comment
Спасибо за ваши подробные объяснения. Возможно, я до сих пор этого не понимаю... но s является целью копии, а не источником, поэтому мне нужно ее видоизменить, выполнение this.wrapped = s никоим образом не изменяет s - person francesc; 26.10.2012
comment
Хм, API для принятия говорит только о том, что принимает соединение. :( Итак, вы имеете в виду, что постусловие this.accept(SocketImpl s) состоит в том, что поля s установлены на те, что для этого??? Это звучит как ужасный дизайн (необходимость видоизменять поля другого объекта). Вы уверены, что не можете спроектировать его наоборот, то есть, что методы только мутируют это? - person DaveFar; 26.10.2012
comment
в основном да, this относится к типу ServerSocket, но содержит необходимую информацию для обновления s. implAccept(Socket s) также ожидает мутации s. Вот как об этом подумали инженеры Sun :-) - person francesc; 26.10.2012
comment
что я не понимаю в вашем ответе, так это зачем нужны методы отражения, это так просто, как accept(SocketImpl s) { s.create(true); s.setPort(port); s.setAddress(addr); ...} - person francesc; 26.10.2012
comment
ладно, я пишу слишком быстро...: MySocketImpl si = s; s.create(true); si.setPort(port); si.setAddress(addr); или ((MySocketImpl)s).setPort(port), если хотите... - person francesc; 26.10.2012