6 Replies Latest reply: Apr 29, 2012 3:54 AM by skiaddict1 RSS

    Need help with generics, I think...

    skiaddict1
      My app has several tables, each of which currently has its own data model. I am in the process of abstracting out the common parts of these models to an abstract superclass, let's call it AbstractModel. The superclass will contain an inner class which will represent a single row of the table's data. Since it also will be abstract, I am calling it AbstractRow. It will contain the fields and methods common to the rows of all data models.

      AbstractModel declares a field, called rows, where the collection of rows is held:
      protected Vector<? extends AbstractRow> rows;
      Each concrete data model will descend from AbstractModel and will contain an inner class which will descend from AbstractRow.

      The constructor for each concrete data model instantiates rows as follows:
      rows = new Vector<MyRow>();
      Now comes my question. Why, oh why, oh why can't I get the following line in my concrete data model to compile?
      rows.add(new MyRow());
      The compiler gives me an error about "add(capture<? extends blahblah.AbstractRow>) in Vector cannot be applied to (blahblah.MyRow)". Nothing I do makes any difference.

      Here is an SSCCE from which the above snippets were taken:
      import java.util.Vector;
      import javax.swing.*;
      
      public class MakeAbstractRowWork extends JPanel
      {
        public abstract class AbstractModel
        {
          protected abstract class AbstractRow
          {
            protected String field1;
            protected String field2;
          }
          protected Vector<? extends AbstractRow> rows;
        }
      
        private class MyModel extends AbstractModel
        {
          protected class MyRow extends AbstractRow
          {
            private String field3;
          }
          MyModel()
          {
            rows = new Vector<MyRow>();
            rows.add(new MyRow()); // this line doesn't compile
          }
        }
        public static void main(String[] args)
        {
          javax.swing.SwingUtilities.invokeLater(new Runnable()
          {
            public void run()
            {
              JFrame frame = new JFrame("MakeAbstractRowWork");
              MakeAbstractRowWork pane = new MakeAbstractRowWork();
              pane.setOpaque(true);
              frame.setContentPane(pane);
              frame.setVisible(true);
            }
          });
        }
      }
      I'd be grateful for any pointers as to how to wrangle my compiler into submission. This, in case it isn't obvious, is my first foray into the world of generics...
        • 1. Re: Need help with generics, I think...
          EJP
          I would make more use of generics:
          // 1. Pull AbstractRow out of the scope of AbstractModel ...
          protected abstract class AbstractRow
          {
            protected String field1;
            protected String field2;
          }
          // ... so that we can use it as an upper bound here
          public abstract class AbstractModel<T extends AbstractRow>
          {
            // You can now initialize 'rows' here, no need to defer that to derived classes
            protected Vector<T> rows = new Vector<T>();
          }
          // Similarly, pull MyModel.MyRow out of that scope so you can use it as a type argument, then:
          protected class MyRow extends AbstractRow
          {
            private String field3;
          }
          // and then do so ...
          private class MyModel extends AbstractModel<MyRow>
          {
            MyModel()
            {
              rows.add(new MyRow());
            }
          Warning: untested, but you get the general idea.
          • 2. Re: Need help with generics, I think...
            skiaddict1
            Far out! Thanks very much :-> I haven't had a chance to migrate the code back to my real project, but this at least compiles.
            • 3. Re: Need help with generics, I think...
              skiaddict1
              I've now migrated the code into my project, and, guess what? It works! :-> :-> :-> My code does exactly what I need it to. Thank you so much, I would never have thought of doing what you suggested. And with a little reflection overnight, I can see what it's doing, so I will even be able to remember this for the future.

              Thanks again
              • 4. Re: Need help with generics, I think...
                skiaddict1
                Several months later and now I realise I need to insert a second parameterised abstract class into my hierarchy, i.e.
                AbstractModel<T extends AbstractRow>
                       |
                       |
                       v
                AbstractTickableModel<T extends AbstractRow>
                       |
                       |
                       v
                MyModel<MyRow>
                I'm having problems, yet again, getting the code to compile. Here is the amended SSCNCE:
                import java.util.Vector;
                import javax.swing.*;
                //------------------------------------------------the rows
                abstract class AbstractRow
                {
                  protected String field1;
                  protected String field2;
                }
                class MyRow extends AbstractRow
                {
                  private String field3;
                }
                //------------------------------------------------the abstract models
                abstract class AbstractModel<T extends AbstractRow>
                {
                  protected Vector<T> rows = new Vector<T>();
                  protected int MIN_ROWS;
                  protected void createMinRows()
                  {
                    for (int i = 0; i < MIN_ROWS; i++)
                    {
                      rows.add(createEmptyRow());
                    }
                  }
                  protected abstract T createEmptyRow();
                }
                abstract class AbstractTickableModel<T extends AbstractRow>
                  extends AbstractModel
                {
                  protected void printRows()
                  {
                    for (AbstractRow row : rows)                                // this line won't compile
                    {
                      System.out.println("field value is " + row.field2);
                    }
                  }
                }
                //------------------------------------------------the concrete model
                class MyModel extends AbstractTickableModel<MyRow>
                {
                  MyModel()
                  {
                    MIN_ROWS = 10;
                    createMinRows();
                  }
                  protected MyRow createEmptyRow()
                  {
                    return new MyRow();
                  }
                }
                //------------------------------------------------infrastructure
                public class DoubleGenerics extends JPanel
                {
                  public static void main(String[] args)
                  {
                    javax.swing.SwingUtilities.invokeLater(new Runnable()
                    {
                      public void run()
                      {
                        JFrame frame = new JFrame("DoubleGenerics");
                        DoubleGenerics pane = new DoubleGenerics();
                        pane.setOpaque(true);
                        frame.setContentPane(pane);
                        frame.setVisible(true);
                        MyModel model = new MyModel();
                      }
                    });
                  }
                }
                This line doesn't compile and gives the error: "Incompatible types: Required: AbstractRow / Found: Object"
                    for (AbstractRow row : rows)
                Please, is some generics whiz able to shed some light on this? I really need a hierarchy like this, and both abstract classes need to be able to talk about the T and S.

                Many TIA!
                • 5. Re: Need help with generics, I think...
                  EJP
                  abstract class AbstractTickableModel<T extends AbstractRow>
                  extends AbstractModel
                  abstract class AbstractTickableModel<T extends AbstractRow>
                    extends AbstractModel<T>
                  • 6. Re: Need help with generics, I think...
                    skiaddict1
                    Many thanks once again EJP :) I did actually try something along those lines, but I included the entire <T extends AbstractRow> thing, which of course wasn't appreciated either...

                    Next time I'll know better!