• Post Reply Bookmark Topic Watch Topic
  • New Topic

Wildcards and generics with enums  RSS feed

 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi; I've written a class that looks like this:



, where ComponentType and Component are empty interface classes that don't inherit or extend anything.

Basically, I want to create a generic table where the key is an enum type that extends ComponentType, and the value is a class that extends Component. However, it seems that I don't understand wildcards in Java very well, because the IDE I'm using reports that the segment of code "get(type)" might have a problem, and that "put(type,component)" has an error. What am I doing wrong?
 
Jesper de Jong
Java Cowboy
Sheriff
Posts: 16059
88
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What are the problem and the error that are reported? Warning and error messages contain important hints about what's wrong, so don't just say "there's a problem" or "there's an error"; include the exact messages.

I can guess what the problem with the put() method is. Suppose you have a List like this:

The wildcard means: you have a list of some definite type that extends Component, but you don't specify what the type is exactly. Because you don't know what the type is (you just know it's some specific type that extends Component), you cannot add anything to the list. An example to illustrate:

In this example, the type of the objects in the list is Integer, but you can't know that by just looking at the type of the variable 'list' (List<? extends Number>). It should not be allowed to add anything that extends Number, because that would mean you could suddenly add a Double to an ArrayList<Integer>.
 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
For the get() method:

Name      public method Component getComponent(int key, ComponentType type)   
Location      class ComponentTable (component)   
Problem synopsis      'EnumMap? extends ComponentType,? extends Component>' may not contain objects of type 'ComponentType' (at line 19)

For the put() method:

java: no suitable method found for put(component.ComponentType,component.Component)
method java.util.EnumMap.put(capture#1 of ? extends component.ComponentType,capture#2 of ? extends component.Component) is not applicable
(actual argument component.ComponentType cannot be converted to capture#1 of ? extends component.ComponentType by method invocation conversion)

Hmm, ultimately, what I would like to do is to make this table a generic table; I plan to have multiple types of components, like maybe CarComponents vs BicycleComponents. Each one would have its own table. Might it fix the problem to declare ArrayList<EnumMap<? extends ComponentType,? extends Component>> table, then instantiate it as, new ArrayList<EnumMap<K,V>(), where K and V are some classes that inherit ComponentType and Component respectively?
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bartholomew Benson wrote:Basically, I want to create a generic table where the key is an enum type that extends ComponentType, and the value is a class that extends Component.

OK, so what about
ArrayList<EnumMap<ComponentType, Component>>
?

Wildcards are generally used in parameter definitions (for precisely the reasons that Jesper explained); you rarely use them when defining fields.

However, I'd back up a bit further: Why do you need (or think you need) such a wide-ranging - not to mention complex - collection?

A Map of ComponentTypes with each value being a List of Components of that type - now that makes sense - but a List of Maps?

However, it may just be me being thick (it's been known ). Would you mind explaining the idea to me?

Winston
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bartholomew Benson wrote:Hmm, ultimately, what I would like to do is to make this table a generic table; I plan to have multiple types of components, like maybe CarComponents vs BicycleComponents. Each one would have its own table. Might it fix the problem to declare ArrayList<EnumMap<? extends ComponentType,? extends Component>> table, then instantiate it as, new ArrayList<EnumMap<K,V>(), where K and V are some classes that inherit ComponentType and Component respectively?

Sorry. I was worked on my response when you posted.

This definitely sounds more like an:
EnumMap<ComponentType, List<Component>>
to me - ie, a Map, where each entry contains a List of Components applicable to the type.

However, there's also some possible duplication here, in that you're using an enum as a type specifier. Now there's nothing particularly wrong with that, but you could get the same effect (I suspect) with an:
IdentityHashMap<Class<? extends Component>, List<Component>>

So is there any particular reason you've chosen to use an enum?

Winston
 
Bartholomew Benson
Greenhorn
Posts: 19
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Basically, I'd like to implement something structured sort of like a relational database, where the columns are the entry's components, and each entry in memory has an int id that fetches that entry's fields as an EnumMap, where every EnumMap represents a row of the table. However, I can't use a java SQL library unless its access speed is on par with direct array access, since I'm expected to constantly read/write this table as fast as I can. ArrayLists seem to be fast enough for most purposes, and I was told that EnumMap is supposed to be a very efficient HashMap using enum keys, so that's why I decided to make it a list of EnumMaps.

After playing around a bit with removing the wildcards, I decided to remove them and replace them with generics. Here's my new code:



The code seems to work now (or at least there are no errors). Thanks, guys!
 
Winston Gutkowski
Bartender
Posts: 10575
66
Eclipse IDE Hibernate Ubuntu
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Bartholomew Benson wrote:Basically, I'd like to implement something structured sort of like a relational database, where the columns are the entry's components, and each entry in memory has an int id that fetches that class's fields as an EnumMap, where every EnumMap represents a row of the table.

OK, but there seems to be an awful lot of "how" in there - ie, you're describing how you want to implement this structure, as opposed to what it's supposed to represent.

So: what is it supposed to represent? I'm still mystified. Try to describe it in terms of Components and Component types. Or, if you prefer, in terms of SQL tables and relationships - I was a DBA for 15 years.

However, I can't use a java SQL library unless its access speed is on par with direct array access, since I'm expected to constantly read/write this table as fast as I can. ArrayLists seem to be fast enough for most purposes, and I was told that EnumMap is supposed to be a very efficient HashMap using enum keys, so that's why I decided to make it a list of EnumMaps.

Again, you're jumping the gun. You're worried about efficiency before you even know whether it's a problem or not. Embedded databases are very fast these days; though whether they're on a par with arrays or not I have no idea. But you shouldn't make your solution reliant on that single issue.

If it was me, my reason for using a Java collection would be that they are native to the language, whereas JDBC is rather clunky; and I really wouldn't give a fig if they're ten times slower until I'd actually worked out that there was a problem.

Winston
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!