For Programmers: Free Programming Magazines  


Home > Archive > Java Help > October 2006 > Generics question









You are viewing an archived Text-only version of the thread. To view this thread in it's original format and/or if you want to reply to this thread please [click here]

 

Author Generics question
Larry Coon

2006-10-13, 10:00 pm

A few days ago I posted a question about implementing
an immutable object in my design (the final answer
being to do it just like Bloch says to do it in
Effective Java).

I'm stuck again with an aspect of this design, this
time involving generics.

To summarize (sorry, this is going to be long winded):
For an application involving university curriculum data,
I have a base class History:

public class History {
. . .
}

which is a base class for course properties:

public class NameHistory extends History {
. . .
}

public class UnitsHistory extends History {
. . .
}

etc. To enforce business rules relating to history
(history must cover the entire timespan in which the
course is active, with no gaps or overlaps, etc.), I
have a "manager" class:

public class ContinuousHistory<T extends History> {
. . .
}

The Course class uses ContinuousHistory as its api to
the history data:

public class Course {
private ContinuousHistory<NameHistory> nameHistory;
private ContinuousHistory<UnitsHistory> unitsHistory;
. . .
}

All well and good so far. This implementation works
great, and there's no way to mess with the History data
without going through the ContinuousHistory manager,
just as I intended.

The user will edit this history data using a JTable,
and I'm writing a JPanel to hold the JTable, which I
can drop into a window to provide editing functionality.

The only difference between the JTable editor for units
vs. the one for course names, vs. the one for titles,
etc., is in the TableModel. I'm trying to define an
abstract HistoryTableModel (which extends
AbstractTableModel). I then extend HistoryTableModel
to define NameTableModel, UnitsTableModel,
TitleTableModel, etc.

Okay that's the background (thanks for reading this far).
Now for the problem.

My HistoryTableModel starts off like this:

public abstract class HistoryTableModel
extends AbstractTableModel {

// I've tried various things here, this is just
// the latest.
protected ContinuousHistory<? extends History> history;

public abstract Object getValueAt(int row, int col);

// This is just an example method.
public final int getRowCount() {
return history.getHistoryData().size();
}

. . .
}

Now here's one of the concrete subclasses:

public class TitleTableModel extends HistoryTableModel {
public TitleTableModel(
ContinuousHistory<? extends History> history)
{
this.history = (ContinuousHistory<TermTypeHistory> )
history;
}

public Object getValueAt(int row, int col) {
TitleHistory th = history.get(row); // COMPILE ERROR

// etc.
}

. . .
}

This implementation won't compile, saying:
Type mismatch: cannot convert from capture-of ? extends
History to TitleHistory
at the spot I indicated above.

What's the right way to declare "history" in class
HistoryTableModel so that it will be a
ContinuousHistory<some class which extends History>,
and the right way to declare the subclass to use it as
a ContinuousHistory<TermTypeHistory> (or whatever other
concrete class)? I've tried a dozen or so different ways,
and I can't find one that works.

Thanks.
Lew

2006-10-13, 10:00 pm

Larry Coon wrote:
> Now here's one of the concrete subclasses:
>
> public class TitleTableModel extends HistoryTableModel {
> public TitleTableModel(
> // inherited: protected ContinuousHistory<? extends History> history;
> ContinuousHistory<? extends History> history)
> {
> this.history = (ContinuousHistory<TermTypeHistory> )
> history;
> }
>
> public Object getValueAt(int row, int col) {
> TitleHistory th = history.get(row); // COMPILE ERROR
>
> // etc.
> }
>
> . . .
> }
>
> This implementation won't compile, saying:
> Type mismatch: cannot convert from capture-of ? extends
> History to TitleHistory
> at the spot I indicated above.


The problem is that the compiler cannot know which subclass of History is in
the type variable, only that it is some subclass of History. Specifically, it
cannot know that the 'history'.get() result is of type 'TitleHistory'.

I'm not entirely sure of the right answer, but I think it's either to declare
history of type ContinuousHistory<TitleHistory> (or '...<? extends
TitleHistory>'), or to use a run-time cast

TitleHistory th = (TitleHistory)history.get(row);

and hope that the get() returns the type that you expect.

I am still learning generics myself, so I welcome more expert comment.

- Lew

Larry Coon

2006-10-13, 10:00 pm

Lew wrote:

> The problem is that the compiler cannot know which subclass of History is in
> the type variable, only that it is some subclass of History. Specifically, it
> cannot know that the 'history'.get() result is of type 'TitleHistory'.
>
> I'm not entirely sure of the right answer, but I think it's either to declare
> history of type ContinuousHistory<TitleHistory> (or '...<? extends
> TitleHistory>'), or to use a run-time cast
>
> TitleHistory th = (TitleHistory)history.get(row);
>
> and hope that the get() returns the type that you expect.
>
> I am still learning generics myself, so I welcome more expert comment.


Thanks for the reply.

I at least got the following to compile, but it doesn't seem like the
right approach.

I moved the declaration of the ContinuousHistory<> out of the
HistoryTableModel base class, and into each of the subclasses,
without the generic aspect.

So I have:

public abstract class HistoryTableModel extends AbstractTableModel {
protected static int[] COLUMN_WIDTHS;

// This depends on the history, so it's now abstract here.
public abstract int getRowCount();

// Doesn't depend on history -- can be implemented here.
public final int getColumnCount() {
return COLUMN_WIDTHS.length;
}

// etc..
}

Now my subclasses contain stuff that I was trying to define in the
base class:

public class UnitsTableModel extends HistoryTableModel {
private ContinuousHistory<UnitsHistory> history;

public UnitsTableModel(ContinuousHistory<UnitsHistory> history) {
COLUMN_WIDTHS = new int[] {20, 20, 50, 50};

this.history = history;
}

public final int getRowCount() {
return history.getHistoryData().size();
}

// etc.
}


public class TitleTableModel extends HistoryTableModel {
private ContinuousHistory<TitleHistory> history;

public TitleTableModel(ContinuousHistory<TitleHistory> history) {
COLUMN_WIDTHS = new int[] {20, 20, 150};

this.history = history;
}

public final int getRowCount() {
return history.getHistoryData().size();
}

// etc.
}

So now every subclass declares history, which is identical in every
implementation, except for the <> history type, which is what I was
trying to make generic. Each subclass also has to provide an
identical implementation of getRowCount() and any other method which
refers to history.

To me, these are big red flags that I'm doing it the wrong way. I
just can't find the right way.
Hendrik Maryns

2006-10-16, 4:05 am

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Larry Coon schreef:
>
> My HistoryTableModel starts off like this:
>
> public abstract class HistoryTableModel
> extends AbstractTableModel {
>
> // I've tried various things here, this is just
> // the latest.
> protected ContinuousHistory<? extends History> history;
>
> public abstract Object getValueAt(int row, int col);
>
> // This is just an example method.
> public final int getRowCount() {
> return history.getHistoryData().size();
> }
>
> . . .
> }
>
> Now here's one of the concrete subclasses:
>
> public class TitleTableModel extends HistoryTableModel {
> public TitleTableModel(
> ContinuousHistory<? extends History> history)
> {
> this.history = (ContinuousHistory<TermTypeHistory> )
> history;
> }
>
> public Object getValueAt(int row, int col) {
> TitleHistory th = history.get(row); // COMPILE ERROR
>
> // etc.
> }
>
> . . .
> }
>
> This implementation won't compile, saying:
> Type mismatch: cannot convert from capture-of ? extends
> History to TitleHistory
> at the spot I indicated above.
>
> What's the right way to declare "history" in class
> HistoryTableModel so that it will be a
> ContinuousHistory<some class which extends History>,
> and the right way to declare the subclass to use it as
> a ContinuousHistory<TermTypeHistory> (or whatever other
> concrete class)? I've tried a dozen or so different ways,
> and I can't find one that works.


How about you pass the information on what type of history you want on
the class level?

public abstract class HistoryTableModel<H extends History>
extends AbstractTableModel {

protected ContinuousHistory<H> history;

// This is just an example method.
public final int getRowCount() {
return history.getHistoryData().size();
}

. . .
}

public class TitleTableModel extends HistoryTableModel<TitleHistory> {
public TitleTableModel(
ContinuousHistory<TitleHistory> history)
{
this.history = history;
}

public Object getValueAt(int row, int col) {
TitleHistory th = history.get(row);

// etc.
}

. . .
}

HTH, H.
- --
Hendrik Maryns
http://tcl.sfs.uni-tuebingen.de/~hendrik/
==================
http://aouw.org
Ask smart questions, get good answers:
http://www.catb.org/~esr/faqs/smart-questions.html
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.2 (GNU/Linux)

iD8DBQFFM072e+7xMGD3itQRAmx4AJ9qbK9nypWq
M336k1vuJlVzS5N77wCeIJa3
NDsgba0IQ8mPVVpjX/H34jM=
=ytMY
-----END PGP SIGNATURE-----
Larry Coon

2006-10-19, 10:00 pm

Hendrik Maryns wrote:

> How about you pass the information on what type of history you want on
> the class level?
>
> public abstract class HistoryTableModel<H extends History>
> extends AbstractTableModel {
>
> protected ContinuousHistory<H> history;
>
> // This is just an example method.
> public final int getRowCount() {
> return history.getHistoryData().size();
> }
>
> . . .
> }
>
> public class TitleTableModel extends HistoryTableModel<TitleHistory> {
> public TitleTableModel(
> ContinuousHistory<TitleHistory> history)
> {
> this.history = history;
> }
>
> public Object getValueAt(int row, int col) {
> TitleHistory th = history.get(row);
>
> // etc.
> }
>
> . . .
> }
>
> HTH, H.


This actually ended up working great for me -- thanks!
Sponsored Links







Also available: Server administration forum archive | Web Design forum archive | Software forum archive | Hardware reviews archive

Copyright 2008 codecomments.com