Старый 29.03.2006, 08:07   #1   
Бывалый форумец
 
Аватар для J++
 
Сообщений: 687
Регистрация: 05.08.2005

J++ вне форума Не в сети
Java-исты, помогите если можете

Удалила в связи с тем, что выяснилось: то, что я хотела, нельзя сделать "прямо". Надо сильно извратиться, выйдя за рамки обычных "путей" на Java.
  Ответить с цитированием
Старый 30.03.2006, 15:41   #2   
Бывалый форумец
 
Аватар для J++
 
Сообщений: 687
Регистрация: 05.08.2005

J++ вне форума Не в сети
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

lordv вне форума Не в сети
Приветствую, 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   
Бывалый форумец
 
Аватар для J++
 
Сообщений: 687
Регистрация: 05.08.2005

J++ вне форума Не в сети
В общем случае - есть базовый класс 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

lordv вне форума Не в сети
Цитата:
Сообщение от J++

В принципе несложно дописать обработчик событитй списка (propertyChange) для класса A1, чтобы слушалось не только старые, но и новое свойство.
Но мне хотелось создать - уже в базовом классе А - универсальный обработчик, такой, чтобы можно было бы только сказать классу A1 (и наследникам): "вот тебе набор свойств - массив типа public static String[] , которые тебе нужно слушать из своего списка". И ВСЕ!
А если завести новый метод getPropertyNames, который будет возвращать массив / список / карту с именами свойств для этого класса? Я бы так сделал:
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   
Бывалый форумец
 
Аватар для J++
 
Сообщений: 687
Регистрация: 05.08.2005

J++ вне форума Не в сети
Спасибо была такая мысль, но я от нее отказалась в силу того, что: а) у меня базовый класс не абстрактный, и абстрактный метод туда не хотелось впихивать; б) зная собственную рассеянность - я могу и забыть переопределить метод в каком-нибудь дальнем потомке, а вот переменная - вроде как вещь простая и ясно "видимая" в тексте (вот горшок пустой, он предмет простой...)

В общем, все эти решения имеют право на существование в разных условиях.
  Ответить с цитированием
Старый 12.04.2006, 10:38   #7   
Форумец
 
Сообщений: 6
Регистрация: 10.04.2006

lordv вне форума Не в сети
Цитата:
Сообщение от J++
а) у меня базовый класс не абстрактный, и абстрактный метод туда не хотелось впихивать;
Где-то уже создаются его экземпляры? Можно тогда сделать ему абстрактного предка с таким методом ;-) Хотя, может, задача не позволяет…
А можно просто в базовом классе выбрасывать там исключение NotSupportedOperationException, например, тогда точно не забудете :-D
Цитата:
Сообщение от J++
б) зная собственную рассеянность - я могу и забыть переопределить метод в каком-нибудь дальнем потомке, а вот переменная - вроде как вещь простая и ясно "видимая" в тексте
С таким же успехом можно забыть про переменную, тем более что её переопределение - не очень-то простая и часто используемая вещь. Сказать честно, ни разу ни в исходниках JDK, ни в живых проектах такого не видел. Только в разных головоломках / тестах по типу BrainBench :-)
К тому же вместо простой операци переопределения метода Вы получили наверняка неочевидный код, использующий Reflection, который выполняет "нецелевую" задачу имитации полиморфизма.
Цитата:
Сообщение от J++
В общем, все эти решения имеют право на существование в разных условиях.
Да. Но я бы съел того, кто завёл бы мне в исходниках переопределение переменной :-) (по-доброму)
  Ответить с цитированием
Старый 12.04.2006, 11:42   #8   
Бывалый форумец
 
Аватар для J++
 
Сообщений: 687
Регистрация: 05.08.2005

J++ вне форума Не в сети
Хм, тут надо рассматривать конкретную ситуацию

дело в том, что написать прямо в классе-потомке, например, переопределение переменной - это простая штука. Все равно ее переопределять - пусть она не 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

lordv вне форума Не в сети
Цитата:
Сообщение от J++
Хотя... можно (попозже) выложить саму задачу и кусок кода на обсуждение и "повертеть" так и сяк.
Да, наверное, так лучше :-)
Цитата:
Сообщение от J++
Ведь придется не забывать в потомках, в каждом (а их может быть до хрена) прописывать какой-нибудь новый getPropertyNames() или то же самое делать в static-блоках... бывает, что не очень весело.
Равно как и переписывать в куче потомков эту переменную :-)
Цитата:
Сообщение от J++
… вот скажите на милость, если есть более совершенный Collection, какого хрена список обработчиков хранится в "древнем" непараметризованном Vector-е? (текст JDK1.5, по-моему класс AbstractAction) .
В AbstractAction не нашёл векторов. Но вообще они, согласен, присутствуют :-) Скорее всего, просто решили не трогать то, что работает - потому что не везде там можно просто поменять в тексте Vector на LinkedList (иногда используют методы вектора, которых нет в других коллекциях).
  Ответить с цитированием
Поиск в теме: 



Быстрый переход:

  Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Powered by vBulletin® Version 3.8.7
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot
Support by DrIQ & Netwind