A musical score contains Item objects. All Items have a Position and associated data. Data can be anything, a note, lyrics, etc.
interface Item<T>
{
Position getPosition();
T getData();
...
}
class NoteItem implements Item<Note>
{
Note getData() { .... }
...
}
class LyricsItem implements Item<Lyrics>
{
Lyrics getData { ... }
...
}
The Score class has a method to get Items of a specific class:
public <T extends Item<E>, E> List<T> getItems(Class<T> itemClass)
{
//
}
As shown below, getItems()
works if parameter is a subclass of Item. But if it's Item.class, return value is a list of objects, I expected a list of Items...
NoteItem item = getItems(NoteItem.class).get(0); // Compiles OK
Item<?> item2= getItems(Item.class).get(0); // Compiles KO, return value is Object, not Item<Object> as I expected
I can fix the 2nd line by explicitly casting the result to (Item<?>), but is there a better way to avoid the casting ?
One solution to avoid the casting is to change the getItems()
method to:
<T> List<T> getItems(Class<T> aClass)
but then the user of the method has no way (besides doc) to know that the method only accepts Item classes. What would be the best way to handle this ?
Not sure it's the best solution but I ended up using the following getItems() method:
<T extends Item<?>> T getItems(Class<T> itemClass);
which makes the 2 lines work:
NoteItem item = getItems(NoteItem.class).get(0); // Compiles OK
Item<?> item2= getItems(Item.class).get(0); // Compiles OK
The only minor drawback is that I get a rawtypes warning when I use getItems(Item.class)
because return value is List<Item>
, not List<Item<?>>
.