Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #34423 > unrolled thread
| Started by | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| First post | 2016-05-31 07:52 -0700 |
| Last post | 2016-06-03 08:52 -0700 |
| Articles | 16 — 4 participants |
Back to article view | Back to comp.lang.java.programmer
How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-05-31 07:52 -0700
Re: How to extend an array Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-05-31 11:52 -0400
Re: How to extend an array Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-05-31 11:56 -0400
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-05-31 09:19 -0700
Re: How to extend an array Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-05-31 14:01 -0400
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-05-31 09:09 -0700
Re: How to extend an array Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-05-31 14:11 -0400
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-05-31 11:25 -0700
Re: How to extend an array Eric Sosman <esosman@comcast-dot-net.invalid> - 2016-05-31 17:01 -0400
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-06-01 04:57 -0700
Re: How to extend an array Roedy Green <inquiry@mindprod.com> - 2016-05-31 21:56 -0700
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-06-01 04:49 -0700
Re: How to extend an array Robert Klemme <shortcutter@googlemail.com> - 2016-06-01 23:07 +0200
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-06-03 05:38 -0700
Re: How to extend an array Robert Klemme <shortcutter@googlemail.com> - 2016-06-04 19:17 +0200
Re: How to extend an array Eric Douglas <e.d.programmer@gmail.com> - 2016-06-03 08:52 -0700
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-05-31 07:52 -0700 |
| Subject | How to extend an array |
| Message-ID | <ae727260-8c33-4648-8995-f387a6eb8b52@googlegroups.com> |
This looks funny but seems to work. Does it make sense, is there better syntax, or anything I'm missing?
I have a custom GUI object which needs to generate custom events, and a more complex version of that object which needs to generate those events plus additional events. Here's a simplified sample.
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.EventListener;
import javax.swing.JFrame;
public abstract class TestStatic {
public static void main(final String[] args) {
final Class2 myWindow = new Class2();
myWindow.addExtendedListener(new Listener2() {
@Override
public void eventWindowOpen() {
System.out.println("opened");
}
@Override
public void additionalMethod() {
}
});
myWindow.setSize(400, 260);
myWindow.setVisible(true);
}
public static class Class1 extends JFrame {
protected ArrayList<Listener1> myArray = new ArrayList();
public Class1() {
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(final WindowEvent e) {
for (final Listener1 l : myArray) {
l.eventWindowOpen();
}
}
});
super.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
public void addListener(final Listener1 addMe) {
myArray.add(addMe);
}
}
public static class Class2 extends Class1 {
protected ArrayList<Listener2> myArray = new ArrayList();
public void addExtendedListener(final Listener2 addMe) {
myArray.add(addMe);
super.myArray.add(addMe);
}
}
public interface Listener1 extends EventListener {
public void eventWindowOpen();
}
public interface Listener2 extends Listener1 {
public void additionalMethod();
}
}
[toc] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-05-31 11:52 -0400 |
| Message-ID | <nikc0f$b0v$1@dont-email.me> |
| In reply to | #34423 |
On 5/31/2016 10:52 AM, Eric Douglas wrote:
> This looks funny but seems to work. Does it make sense, is there better syntax, or anything I'm missing?
> I have a custom GUI object which needs to generate custom events, and a more complex version of that object which needs to generate those events plus additional events. Here's a simplified sample.
> [... code snipped; see up-thread ...]
I don't see why Class2 needs its own list of listeners, nor its
addExtendedListener() method. Since Listener2 extends Listener1, a
Listener2 "is a" Listener1 and can be handled just fine by Class1's
addListener() method. Unless there's some additional concern that
you've simplified away, I think you're working too hard.
Side-issue: Since Class1 and Class2 extend JFrame, they are both
Swing components. Swing components are not thread-safe (by and large),
so it's not safe to manipulate them from more than one thread. That
thread should be the Event Dispatch Thread or EDT. Your code, though,
does a *lot* of manipulation of these Swing components on a non-EDT
thread: It constructs them, resizes their windows, and makes them
visible, all from the startup thread that calls main(). Don't Do That.
(To be fair to you, Sun themselves didn't at first realize this was a
no-no, and some of the early Swing examples commit this same error.
Pay attention to more up-to-date examples, that's all I can suggest.)
One simple way to ensure that construction happens on the EDT:
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
Class2 myWindow = new Class2();
... et cetera ...
myWindow.setVisible(true);
});
(The fashion nowadays is to use a "lambda expression" instead of an
explicit "new Runnable()", but I didn't want to risk spooking you.)
For "belt and suspenders" safety, I also like to sprinkle
assert SwingUtilities.isEventDispatchThread();
in the constructors of my Swingthings, and in some of their public
methods as well -- Better to get crashes during development and test
than to get baffling unreproducible failures at deployment ...
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-05-31 11:56 -0400 |
| Message-ID | <nikc72$c5q$1@dont-email.me> |
| In reply to | #34424 |
On 5/31/2016 11:52 AM, Eric Sosman wrote:
> [...]
> One simple way to ensure that construction happens on the EDT:
>
> public static void main(String[] args) {
> SwingUtilities.invokeLater(new Runnable() {
> Class2 myWindow = new Class2();
> ... et cetera ...
> myWindow.setVisible(true);
> });
>
> (The fashion nowadays is to use a "lambda expression" instead of an
> explicit "new Runnable()", but I didn't want to risk spooking you.)
... and while de-lambda-izing my spooky example, I botched it.
Sorry; that should have been
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
Class2 myWindow = new Class2();
... et cetera ...
myWindow.setVisible(true);
}
});
(Sigh.)
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-05-31 09:19 -0700 |
| Message-ID | <0ef8b15c-b3d1-4e80-b3ac-2fc577b6569f@googlegroups.com> |
| In reply to | #34425 |
On Tuesday, May 31, 2016 at 11:56:29 AM UTC-4, Eric Sosman wrote:
> Sorry; that should have been
>
> public static void main(String[] args) {
> SwingUtilities.invokeLater(new Runnable() {
I looked that up once and found that SwingUtilities.invokeLater was a way to run something on the EDT way back in Java 1.1 which was later changed to just call EventQueue.invokeLater, so you can use either and there shouldn't be any noticeable difference.
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-05-31 14:01 -0400 |
| Message-ID | <nikjh6$7ud$1@dont-email.me> |
| In reply to | #34427 |
On 5/31/2016 12:19 PM, Eric Douglas wrote:
> On Tuesday, May 31, 2016 at 11:56:29 AM UTC-4, Eric Sosman wrote:
>> Sorry; that should have been
>>
>> public static void main(String[] args) {
>> SwingUtilities.invokeLater(new Runnable() {
>
> I looked that up once and found that SwingUtilities.invokeLater was a way to run something on the EDT way back in Java 1.1 which was later changed to just call EventQueue.invokeLater, so you can use either and there shouldn't be any noticeable difference.
Yeah, but you've got to use *something* to ensure that Swingstuff
gets done on the EDT, and not on other threads.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-05-31 09:09 -0700 |
| Message-ID | <f46278e9-a64d-42d4-8c2d-5e0cfd168692@googlegroups.com> |
| In reply to | #34424 |
On Tuesday, May 31, 2016 at 11:53:00 AM UTC-4, Eric Sosman wrote: > I don't see why Class2 needs its own list of listeners, nor its > addExtendedListener() method. Since Listener2 extends Listener1, a > Listener2 "is a" Listener1 and can be handled just fine by Class1's > addListener() method. Unless there's some additional concern that > you've simplified away, I think you're working too hard. > > Side-issue: Since Class1 and Class2 extend JFrame, they are both > Swing components. Swing components are not thread-safe (by and large), > so it's not safe to manipulate them from more than one thread. That > thread should be the Event Dispatch Thread or EDT. Your code, though, > does a *lot* of manipulation of these Swing components on a non-EDT > thread: It constructs them, resizes their windows, and makes them > visible, all from the startup thread that calls main(). Don't Do That. > (To be fair to you, Sun themselves didn't at first realize this was a > no-no, and some of the early Swing examples commit this same error. > Pay attention to more up-to-date examples, that's all I can suggest.) As I mentioned this is a simple sample to show the structure, so yes those are non issues. You see Listener2 has additional methods. Class2 in the sample didn't call the method(s) but will need to. Test programs instantiating a Class1 will need to handle all Listener1 methods. Test programs instantiating a Class2 will need to handle all Listener1 methods plus the additional methods in Listener2. The second issue, yes, Eclipse runs this sample as is and I left it out but I do normally instantiate the Swing GUI objects (JFrame, or JDialog) from an EventQueue.invokeLater(). The question here is about the array. Does this make sense, having a class extending a class overriding a method that accepts an object for an array with a class which extends that object's class, just using an array of the same name and having to add it to that array plus the super...?
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-05-31 14:11 -0400 |
| Message-ID | <nikk4d$ao3$1@dont-email.me> |
| In reply to | #34426 |
On 5/31/2016 12:09 PM, Eric Douglas wrote:
> On Tuesday, May 31, 2016 at 11:53:00 AM UTC-4, Eric Sosman wrote:
>> I don't see why Class2 needs its own list of listeners, nor its
>> addExtendedListener() method. Since Listener2 extends Listener1, a
>> Listener2 "is a" Listener1 and can be handled just fine by Class1's
>> addListener() method. Unless there's some additional concern that
>> you've simplified away, I think you're working too hard.
>>
>> Side-issue: Since Class1 and Class2 extend JFrame, they are both
>> Swing components. Swing components are not thread-safe (by and large),
>> so it's not safe to manipulate them from more than one thread. That
>> thread should be the Event Dispatch Thread or EDT. Your code, though,
>> does a *lot* of manipulation of these Swing components on a non-EDT
>> thread: It constructs them, resizes their windows, and makes them
>> visible, all from the startup thread that calls main(). Don't Do That.
>> (To be fair to you, Sun themselves didn't at first realize this was a
>> no-no, and some of the early Swing examples commit this same error.
>> Pay attention to more up-to-date examples, that's all I can suggest.)
>
> As I mentioned this is a simple sample to show the structure, so yes those are non issues. You see Listener2 has additional methods. Class2 in the sample didn't call the method(s) but will need to. Test programs instantiating a Class1 will need to handle all Listener1 methods. Test programs instantiating a Class2 will need to handle all Listener1 methods plus the additional methods in Listener2. The second issue, yes, Eclipse runs this sample as is and I left it out but I do normally instantiate the Swing GUI objects (JFrame, or JDialog) from an EventQueue.invokeLater().
It doesn't matter that Listener2 has additional methods beyond those
of its base interface Listener1: Any class that implements Listener2
perforce implements Listener1, so a Listener2 implementation "is a"
Listener1 implementation, and can be handed to Class1's addListener().
In fact, in your sketch you do exactly this: Class2 hands the Listener2
it is given to its Class1 superclass, which accepts it because ... it
"is a" Listener1.
As for users of Class2 being required to handle the additional
methods of Listener2 -- well, I'm afraid I don't see the need. Since
a Class2 "is a" Class1, a user of Class2 instances should be able to
treat them as Class1 instances (because they "are"), and should thus
be able to deal with Listener1 events alone. If for some reason this
is not possible, I think there's something highly suspect about your
design: It's like "MyList extends AbstractList, but you can't treat it
like a List." Perhaps a less "simplified" example would help ...
> The question here is about the array. Does this make sense, having a class extending a class overriding a method that accepts an object for an array with a class which extends that object's class, just using an array of the same name and having to add it to that array plus the super...?
Since I'm still not sure I understand what you're trying to do,
I can't comment. Not usefully, anyhow.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-05-31 11:25 -0700 |
| Message-ID | <d8ea605f-0759-4b10-b293-235cc558d6e9@googlegroups.com> |
| In reply to | #34429 |
On Tuesday, May 31, 2016 at 2:11:36 PM UTC-4, Eric Sosman wrote:
> Since I'm still not sure I understand what you're trying to do,
> I can't comment. Not usefully, anyhow.
So, the same sample with the missing pieces you mentioned. Class1 is a customized JFrame. In this example it's just a default JFrame with a default close operation automatically set and a default window listener created. Class2 is a customized Class1. In this example it just adds another default to report window iconified (minimize) events. Does this structure make sense, just making an array in the extended class (which apparently adds a second array on top of the one in the super class even if I make that visible and give the second one the same name), passing listeners into both arrays from the second class?
In the full super complicated API, Class1 extends a JTable and reports table events like row change, and Class2 is a fancier Class1 table with all it's fonts, colors, events, etc which adds a JTree. The JTree renders one column and passes MouseEvents through to report tree events like treeWillExpand, reporting a tree node which is rendered in a single cell which triggers to add nodes which inserts rows...
import java.awt.EventQueue;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.util.ArrayList;
import java.util.EventListener;
import javax.swing.JFrame;
public abstract class TestStatic2 {
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
final Class2 myWindow = new Class2();
myWindow.addExtendedListener(new Listener2() {
@Override
public void eventWindowOpen() {
System.out.println("opened");
}
@Override
public void eventWindowIconified() {
System.out.println("iconified");
}
});
myWindow.setSize(400, 260);
myWindow.setVisible(true);
}
});
}
public static class Class1 extends JFrame {
protected ArrayList<Listener1> myArray = new ArrayList();
public Class1() {
addWindowListener(new WindowAdapter() {
@Override
public void windowOpened(final WindowEvent e) {
for (final Listener1 l : myArray) {
l.eventWindowOpen();
}
}
});
super.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
}
public void addListener(final Listener1 addMe) {
myArray.add(addMe);
}
}
public static class Class2 extends Class1 {
protected ArrayList<Listener2> myArray = new ArrayList();
public Class2() {
addWindowListener(new WindowAdapter() {
@Override
public void windowIconified(WindowEvent e) {
for (final Listener2 l : myArray) {
l.eventWindowIconified();
}
}
});
}
public void addExtendedListener(final Listener2 addMe) {
myArray.add(addMe);
super.myArray.add(addMe);
}
}
public interface Listener1 extends EventListener {
public void eventWindowOpen();
}
public interface Listener2 extends Listener1 {
public void eventWindowIconified();
}
}
[toc] | [prev] | [next] | [standalone]
| From | Eric Sosman <esosman@comcast-dot-net.invalid> |
|---|---|
| Date | 2016-05-31 17:01 -0400 |
| Message-ID | <niku2v$hhp$1@dont-email.me> |
| In reply to | #34430 |
On 5/31/2016 2:25 PM, Eric Douglas wrote:
> On Tuesday, May 31, 2016 at 2:11:36 PM UTC-4, Eric Sosman wrote:
>> Since I'm still not sure I understand what you're trying to do,
>> I can't comment. Not usefully, anyhow.
>
> So, the same sample with the missing pieces you mentioned. Class1 is a customized JFrame. In this example it's just a default JFrame with a default close operation automatically set and a default window listener created. Class2 is a customized Class1. In this example it just adds another default to report window iconified (minimize) events. Does this structure make sense, just making an array in the extended class (which apparently adds a second array on top of the one in the super class even if I make that visible and give the second one the same name), passing listeners into both arrays from the second class?
> [... see up-thread for code ...]
I'm afraid I still can't understand what you're up to. It seems a
Class2 instance will have listeners of two kinds, and will maintain two
references to some of them:
- A Listener1 registered with addListener() will appear in one
list of listeners,
- A Listener2 registered with addExtendedListener() will appear
in two lists of listeners, once in its Listener2 aspect and
again as its Listener1 superinterface.
I'm at a loss to understand why you want the Listener2's double-
registered, held in two lists. Since the list in Class1 appears to
serve no purpose (listeners get added to it and thereafter ignored),
it seems likely that further detail has been simplified away -- but
simplified to the extent that I cannot divine what you're about.
It's over my head, I fear.
--
esosman@comcast-dot-net.invalid
"Don't be afraid of work. Make work afraid of you." -- TLM
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-06-01 04:57 -0700 |
| Message-ID | <e85ae3a6-8c82-4232-8967-559ee31b21bc@googlegroups.com> |
| In reply to | #34431 |
On Tuesday, May 31, 2016 at 5:01:35 PM UTC-4, Eric Sosman wrote: > I'm afraid I still can't understand what you're up to. It seems a > Class2 instance will have listeners of two kinds, and will maintain two > references to some of them: > > - A Listener1 registered with addListener() will appear in one > list of listeners, > > - A Listener2 registered with addExtendedListener() will appear > in two lists of listeners, once in its Listener2 aspect and > again as its Listener1 superinterface. > correct > I'm at a loss to understand why you want the Listener2's double- > registered, held in two lists. Since the list in Class1 appears to > serve no purpose (listeners get added to it and thereafter ignored), > it seems likely that further detail has been simplified away -- but > simplified to the extent that I cannot divine what you're about. > It's over my head, I fear. Normally an instance of Class1 will only want a Listener1 type listener, and a Class2 will only want a Listener2 type listener. Class1 is the base class. In this example it's a custom JFrame. In the complicated API it's a customized JTable. It reports those simple events. In the example it's reporting window opened. In the complicated API it's reporting everything JTable related - focus gained, row changed, start edit, etc. Class2 is the extension of Class1. It doesn't need to repeat what Class1 is doing. In this example Class1 reports window opened for a Class2 window, and Class2 reports the window minimized. In the complicated API I'm displaying one JTable column using a JTree. Mouse clicks on that JTable pass through to the JTree, so you can click a node and expand it, and it inserts rows to the table. This needs all the standard JTable events, which still report from the base custom class, plus it needs the extended class to report the tree node expanding and all such related events.
[toc] | [prev] | [next] | [standalone]
| From | Roedy Green <inquiry@mindprod.com> |
|---|---|
| Date | 2016-05-31 21:56 -0700 |
| Message-ID | <mmqskb9rkncdn1oko5207at1poq140vkqp@4ax.com> |
| In reply to | #34423 |
On Tue, 31 May 2016 07:52:22 -0700 (PDT), Eric Douglas
<e.d.programmer@gmail.com> wrote:
> public void addListener(final Listener1 addMe) {
> myArray.add(addMe);
JComponent has all kinds of methods for adding and removing Listeners.
If you extended JComponent, all the listener logic woud come along
free.
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-06-01 04:49 -0700 |
| Message-ID | <dc3cb6b6-c664-4349-a463-422c69e774d2@googlegroups.com> |
| In reply to | #34433 |
On Wednesday, June 1, 2016 at 12:57:10 AM UTC-4, Roedy Green wrote: > JComponent has all kinds of methods for adding and removing Listeners. > If you extended JComponent, all the listener logic woud come along > free. I'm adding custom listeners, not Java listeners. The classes themselves have their own Java listeners to handle events and call the methods of the custom listeners. One custom listener can execute a focus lost, a grid row change, and anything else relevant to that control. Sometimes it may just merge these events. Sometimes it's a lot of custom Java listener logic the main class creating the custom GUI object doesn't need to or want to handle. For instance if a grid (JTable) gains focus I only want a focus gain event once for all of it. The focus listeners report all the little events, when the focus moves to the scrollpane, to the grid, to the header, to the cell editor. I custom report all relevant events to make it easier for the application.
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2016-06-01 23:07 +0200 |
| Message-ID | <dr914vFsbd4U1@mid.individual.net> |
| In reply to | #34423 |
On 31.05.2016 16:52, Eric Douglas wrote:
> This looks funny but seems to work. Does it make sense, is there
> better syntax, or anything I'm missing?
First of all: the title is totally misleading. This is not about
arrays, it's about ArrayLists - even about generic collections generally.
After reading the thread it seems you might want parallel inheritance
hierarchies like this:
package listeners;
public interface BaseListener {
void fast(final BaseClass<?> o);
}
package listeners;
import java.util.ArrayList;
import java.util.List;
public class BaseClass<L extends BaseListener> {
private final List<L> listeners = new ArrayList<>();
protected List<L> getListeners() {
return listeners;
}
public void addListener(final L listener) {
getListeners().add(listener);
}
public void notifyFast() {
for (final L listener : getListeners()) {
listener.fast(this);
}
}
}
package listeners;
public interface DerivedListener extends BaseListener {
void superFast(final DerivedClass<?> o);
}
package listeners;
public class DerivedClass<L extends DerivedListener>
extends BaseClass<L> {
public void notifySuperFast() {
for (final L listener : getListeners()) {
listener.superFast(this);
}
}
}
Is this what you had in mind?
Kind regards
robert
--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-06-03 05:38 -0700 |
| Message-ID | <38f6b479-51a0-4bc3-b1f7-f05d3d229f53@googlegroups.com> |
| In reply to | #34437 |
On Wednesday, June 1, 2016 at 5:07:55 PM UTC-4, Robert Klemme wrote:
> Is this what you had in mind?
>
> Kind regards
>
> robert
I modified your sample into a runnable static class. It appears that would work, to put the listeners for both classes into a single array, with some slight confusion to avoid.
import java.util.ArrayList;
import java.util.List;
public class TestStatic3 {
public static void main(final String[] args) {
final BaseClass bc = new BaseClass();
bc.addListener(new BaseListener() {
@Override
public void fast(final BaseClass<?> o) {
System.out.println("simple bc");
}
});
final DerivedClass dc = new DerivedClass();
dc.addListener(new DerivedListener() {
@Override
public void fast(final BaseClass<?> o) {
System.out.println("simple dc");
}
@Override
public void superFast(final DerivedClass<?> o) {
System.out.println("more complex dc");
}
});
// this does compile,
// will get a runtime error when class tries to execute superFast()
dc.addListener(new BaseListener() {
@Override
public void fast(final BaseClass<?> o) {
System.out.println("simple dc");
}
});
// this does compile and runs fine,
// will never execute the superFast
bc.addListener(new DerivedListener() {
@Override
public void fast(final BaseClass<?> o) {
System.out.println("simple bc");
}
@Override
public void superFast(final DerivedClass<?> o) {
System.out.println("more complex bc");
}
});
bc.notifyFast();
dc.notifyFast();
dc.notifySuperFast();
System.out.println("done");
}
public static interface BaseListener {
void fast(final BaseClass<?> o);
}
public static class BaseClass<L extends BaseListener> {
private final List<L> listeners = new ArrayList<>();
protected List<L> getListeners() {
return listeners;
}
public void addListener(final L listener) {
getListeners().add(listener);
}
public void notifyFast() {
for (final L listener : getListeners()) {
listener.fast(this);
}
}
}
public static interface DerivedListener extends BaseListener {
void superFast(final DerivedClass<?> o);
}
public static class DerivedClass<L extends DerivedListener> extends BaseClass<L> {
public void notifySuperFast() {
for (final L listener : getListeners()) {
listener.superFast(this);
}
}
}
}
I think the way I wrote it may have more overhead but avoids those issues, should get a compile error if you try to add the extended listener to the base class instance, and should work fine only executing base listener events if you add the base listener to the extended class instance.
I don't think those issues should ever come up, normally we'll only want a base listener for a base class instance and a derived listener for an extended class instance, but a lot of problems do come up in programming when an API allows someone to do something they should never do.
(thorough documentation emphasizing what not to do helps?)
[toc] | [prev] | [next] | [standalone]
| From | Robert Klemme <shortcutter@googlemail.com> |
|---|---|
| Date | 2016-06-04 19:17 +0200 |
| Message-ID | <drggppFctmpU1@mid.individual.net> |
| In reply to | #34454 |
On 03.06.2016 14:38, Eric Douglas wrote: > On Wednesday, June 1, 2016 at 5:07:55 PM UTC-4, Robert Klemme wrote: >> Is this what you had in mind? > I modified your sample into a runnable static class. It appears that > would work, to put the listeners for both classes into a single > array, with some slight confusion to avoid. You omitted the generic declarations which defies the whole point of using them. You should have noticed by the warnings that you should be getting. > I think the way I wrote it may have more overhead but avoids those > issues, should get a compile error if you try to add the extended > listener to the base class instance, Why? Because the "extended listener" extends the base listener. And it is completely logical that you do _not_ get a compile error. > and should work fine only > executing base listener events if you add the base listener to the > extended class instance. You cannot do that because a BaseListener does not extend DerivedListener. The compiler will prevent this. > I don't think those issues should ever come up, normally we'll only > want a base listener for a base class instance and a derived listener > for an extended class instance, but a lot of problems do come up in > programming when an API allows someone to do something they should > never do. (thorough documentation emphasizing what not to do helps?) I think you still have not grasped it fully how this works. I am not even sure what you are trying to achieve. Can you describe that in plain English? Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/
[toc] | [prev] | [next] | [standalone]
| From | Eric Douglas <e.d.programmer@gmail.com> |
|---|---|
| Date | 2016-06-03 08:52 -0700 |
| Message-ID | <de7842b3-934b-46d9-bcda-42034e0eabdb@googlegroups.com> |
| In reply to | #34437 |
On Wednesday, June 1, 2016 at 5:07:55 PM UTC-4, Robert Klemme wrote:
> After reading the thread it seems you might want parallel inheritance
> hierarchies like this:
I've never used that syntax before. So if we want to implement a second set of extended interfaces like that we just add it into that block, then every reference needs another "?" ?
import java.util.ArrayList;
import java.util.List;
import javax.swing.Icon;
public class TestStatic3 {
public static void main(final String[] args) {
final BaseClass bc = new BaseClass();
bc.addListener(new BaseListener() {
@Override
public void fast(final BaseClass<?, ?> o) {
System.out.println("simple bc");
}
});
final DerivedClass dc = new DerivedClass();
dc.addListener(new DerivedListener() {
@Override
public void fast(final BaseClass<?, ?> o) {
System.out.println("simple dc");
}
@Override
public void superFast(final DerivedClass<?, ?> o) {
System.out.println("more complex dc");
}
});
bc.notifyFast();
dc.notifyFast();
dc.notifySuperFast();
System.out.println("done");
}
public static interface BaseListener {
void fast(final BaseClass<?, ?> o);
}
public static class BaseClass<L extends BaseListener, I extends Icon> {
private final List<L> listeners = new ArrayList<>();
protected List<L> getListeners() {
return listeners;
}
public void addListener(final L listener) {
getListeners().add(listener);
}
public void notifyFast() {
for (final L listener : getListeners()) {
listener.fast(this);
}
}
}
public static interface DerivedListener extends BaseListener {
void superFast(final DerivedClass<?, ?> o);
}
public static interface CustomIcon extends Icon {
}
public static class DerivedClass<L extends DerivedListener, I extends CustomIcon> extends BaseClass<L, I> {
public void notifySuperFast() {
for (final L listener : getListeners()) {
listener.superFast(this);
}
}
}
}
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.java.programmer
csiph-web