Если это ваш первый визит, рекомендуем почитать справку по форуму. Для размещения своих сообщений необходимо зарегистрироваться. Для просмотра сообщений выберите раздел. |
Java-исты, помогите если можете |
Философия, технологии, алгоритмы! |
|
Опции темы |
30.03.2006, 15:41 | #2 |
Бывалый форумец
Сообщений: 687
Регистрация: 05.08.2005
Не в сети |
PS. А ведь сделала!
Если кому интересно, задачка была примерно такая: есть класс A class A { .... protected static String[] S={"1", "2"}; // именно static! ....... // тут конструкторы всякие ....... public static showS(){ for (int i=0; i<S.length; i++) System.out.println(S[i]); } } и класс B class B extends A { // эта переменная ДОЛЖНА быть // перегружаема в потомках! protected static String[] S={"1", "2", "3", "4"} ; .... // тут конструкторы // а метод showS() НЕ перегружен! } создаем объекты: A a=new A(); a.showS(); печатается: 1 2 B b=new B(); b.showS(); печатается то же самое, что и для a, хотя хочется, чтобы было 1 2 3 4 . Задача: нужно написать класс A и метод showS() таким образом, чтобы в потомках можно было бы только переопределять переменную S (не меняя типа), а метод showS() не нужно перегружать, но чтобы он работал и выдавал именно то содержимое S, что в текущем классе (из которого его вызвали). При этом чтобы не нужно было запихивать в конструкторы (или в static-блоки) классов-потомков никаких дополнительных инициализаций. Сделала но переменную S пришлось сделать public static String[]. Кто хочет, кому интересно - пишите ваши догадки А может ваши варианты окажутся лучше и проще моего |
10.04.2006, 18:36 | #3 |
Форумец
Сообщений: 6
Регистрация: 10.04.2006
Не в сети |
Приветствую, J++!
[quot] Кто хочет, кому интересно - пишите ваши догадки [/quot] Никаких догадок не надо. По-моему, эта штука в спецификации называется hiding, и смысл её в том, что для статических методов / полей не происходит позднего связывания - т.е. обращение идёт к полю / методу не фактического класса, а того, который был указан при её объявлении (или приведении типа). Предположим, A - предок, SubclassA - потомок, у обоих есть статический метод method() с одинаковой сигнатурой : A a = new SubclassA(); a.method(); // вызов method класса A ((SubclassA) a).method(); // вызов method класса B Что делать в Вашей ситуации - я не знаю. Похоже на косяки в дизайне :-) Кроме извращений с передачей объекта в show и извлечения у него этого поля через Reflection ничего на ум не идёт. Но я на 100% уверен, что можно было обойтись без таких извращений в дизайне :-) Расскажите задачу хоть ;-) |
11.04.2006, 13:15 | #4 |
Бывалый форумец
Сообщений: 687
Регистрация: 05.08.2005
Не в сети |
В общем случае - есть базовый класс A, и есть список, в который помещаются объекты класса A. Назовем класс списка - AList.
Cписок "управляет" некоторыми свойствами объектов, помещенных в него. Допустим, в списке есть свойство "aaa", и в каждом члене списка есть свойство "aaa". Когда в списке изменилось значение этого "ааа" - надо, чтобы и в членах списка оно изменилось так же. Тут все просто: класс А слушает "свой" заданный набор свойств из списка, все хорошо (слушает propertyChange класса AList). Но вот захотели мы создать класс A1, порожденный от A, и в нем есть новое свойство "bbb". И делаем список, порожденный от AList - Alist1, в котором тоже есть свойство "bbb". Надо бы теперь его тоже слушать из списка. В принципе несложно дописать обработчик событитй списка (propertyChange) для класса A1, чтобы слушалось не только старые, но и новое свойство. Но мне хотелось создать - уже в базовом классе А - универсальный обработчик, такой, чтобы можно было бы только сказать классу A1 (и наследникам): "вот тебе набор свойств - массив типа public static String[] , которые тебе нужно слушать из своего списка". И ВСЕ! Т.е. НЕ переопределять никакие propertyChange в классах-наследниках для все новых и новых свойств, а чтобы просто сделать вот так, как показано в примере: переопределил в наследнике public static String[] S - и дело в шляпе. Хотя бы потому, что лень-матушка для каждого наследника переписывать обработчики Ну да, все получилось через reflection. Я не думаю что это проблемы дизайна, хотя может и неправа. |
12.04.2006, 07:28 | #5 | |
Форумец
Сообщений: 6
Регистрация: 10.04.2006
Не в сети |
Цитата:
public class AList { /* * В наследниках завести аналогичное поле. */ private static final String[] names = new String[] {"a", "b"}; /** * Его переопределять в наследниках. А тут можно сделать и * абстрактным, чтобы заставить потомков переопределять его. */ protected String[] getPropertyNames() { return names; } /** * Этот метод общий для всех наследников, он определён раз * и навсегда, например. */ public final void doSmth() { … String[] array = getPropertyNames(); // Вызов переопределённого метода. … } } |
|
12.04.2006, 07:39 | #6 |
Бывалый форумец
Сообщений: 687
Регистрация: 05.08.2005
Не в сети |
Спасибо была такая мысль, но я от нее отказалась в силу того, что: а) у меня базовый класс не абстрактный, и абстрактный метод туда не хотелось впихивать; б) зная собственную рассеянность - я могу и забыть переопределить метод в каком-нибудь дальнем потомке, а вот переменная - вроде как вещь простая и ясно "видимая" в тексте (вот горшок пустой, он предмет простой...)
В общем, все эти решения имеют право на существование в разных условиях. |
12.04.2006, 10:38 | #7 | |||
Форумец
Сообщений: 6
Регистрация: 10.04.2006
Не в сети |
Цитата:
А можно просто в базовом классе выбрасывать там исключение NotSupportedOperationException, например, тогда точно не забудете :-D Цитата:
К тому же вместо простой операци переопределения метода Вы получили наверняка неочевидный код, использующий Reflection, который выполняет "нецелевую" задачу имитации полиморфизма. Цитата:
|
|||
12.04.2006, 11:42 | #8 |
Бывалый форумец
Сообщений: 687
Регистрация: 05.08.2005
Не в сети |
Хм, тут надо рассматривать конкретную ситуацию
дело в том, что написать прямо в классе-потомке, например, переопределение переменной - это простая штука. Все равно ее переопределять - пусть она не public static, так private, один хрен без этой строчки не обойдется. getPropertyNames() больше чем наполовину основывается на этом же, только сама переменная "спрятана" в private. Что, безусловно, с точки зрения сокрытия более правильно, но выигрыш (для меня) в этом неочевиден: все равно писать лишние буквы теперь уже для getPropertyNames() - с которого может быть, навара особого нет. Поскольку переменная - static. Хотя... можно (попозже) выложить саму задачу и кусок кода на обсуждение и "повертеть" так и сяк. Ведь придется не забывать в потомках, в каждом (а их может быть до хрена) прописывать какой-нибудь новый getPropertyNames() или то же самое делать в static-блоках... бывает, что не очень весело. Кстати, именно вариант static-блока я испробовала первым. Что-то мне там не понравилось, и я сделала так, как сделала... пока. Ладно, допишу все это дело, выложу. Это и правда из разряда извратов, но получилось ИМХО довольно красиво и просто в работе, к тому же безопасно в работе и с точки зрения наследования (самой непонятно - то ли восхищаться, то ли возмущаться собственными вывертами ). PS. А в исходниках JDK много интересного можно увидеть - и в хорошем, и в плохом смысле вот скажите на милость, если есть более совершенный Collection, какого хрена список обработчиков хранится в "древнем" непараметризованном Vector-е? (текст JDK1.5, по-моему класс AbstractAction) . Ведь все равно "наружу" торчат все те же методы, при переходе на 1.5 пользователю не придется в этом плане ничего менять. А как там внутри сделать - целиком на совести разработчиков. |
12.04.2006, 12:26 | #9 | |||
Форумец
Сообщений: 6
Регистрация: 10.04.2006
Не в сети |
Цитата:
Цитата:
Цитата:
|
|||