Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.java.programmer > #34423 > unrolled thread

How to extend an array

Started byEric Douglas <e.d.programmer@gmail.com>
First post2016-05-31 07:52 -0700
Last post2016-06-03 08:52 -0700
Articles 16 — 4 participants

Back to article view | Back to comp.lang.java.programmer


Contents

  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

#34423 — How to extend an array

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-05-31 07:52 -0700
SubjectHow 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]


#34424

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-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]


#34425

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-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]


#34427

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34428

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-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]


#34426

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34429

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-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]


#34430

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34431

FromEric Sosman <esosman@comcast-dot-net.invalid>
Date2016-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]


#34435

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34433

FromRoedy Green <inquiry@mindprod.com>
Date2016-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]


#34434

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34437

FromRobert Klemme <shortcutter@googlemail.com>
Date2016-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]


#34454

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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]


#34462

FromRobert Klemme <shortcutter@googlemail.com>
Date2016-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]


#34455

FromEric Douglas <e.d.programmer@gmail.com>
Date2016-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