2

I am trying to store objects that are a sub-class of an abstract class, but there is a problem illustrated here:

abstract class Letter {
    public void store_object(Letter letter) {
        HashMap<Class<? extends Letter>, ? extends Letter> map = new HashMap<>();
        map.put(letter.getClass(), letter); <-- this line throws an error
    }
}
class A extends Letter {}
class B extends Letter {}

The reason map.put throws an error is that letter is not a sub-class of Letter (it is a direct instance of Letter).

Is there a way to change the method parameter to be a generic sub-class of Letter? Something like:

public void store_object(? extends Letter letter) {

or

public void store_object(Object<? extends Letter> letter) {

The error is:

no suitable method found for put(Class<CAP#1>,NewClass19.Letter)
    method Map.put(Class<? extends NewClass19.Letter>,CAP#2) is not applicable
      (argument mismatch; NewClass19.Letter cannot be converted to CAP#2)
    method AbstractMap.put(Class<? extends NewClass19.Letter>,CAP#2) is not applicable
      (argument mismatch; NewClass19.Letter cannot be converted to CAP#2)
    method HashMap.put(Class<? extends NewClass19.Letter>,CAP#2) is not applicable
      (argument mismatch; NewClass19.Letter cannot be converted to CAP#2)
  where CAP#1,CAP#2 are fresh type-variables:
    CAP#1 extends NewClass19.Letter from capture of ? extends NewClass19.Letter
    CAP#2 extends NewClass19.Letter from capture of ? extends NewClass19.Letter
ryvantage
  • 13,064
  • 15
  • 63
  • 112
  • Can you post the exact error? And also, what do you mean by `it is a direct instance of Letter`? If `Letter` is abstract, how can you have a direct instance of it? – sstan Jul 19 '15 at 02:46
  • The error is posted. It relates to the fact that the `HashMap` is expecting a variable of type `? extends Letter` but instead it got a variable of type `Letter`. When I said "direct instance of `Letter`, this is what I was referring to. – ryvantage Jul 19 '15 at 02:50
  • Instead of using a `Map` you could use a `Set` and if you need to know the type somewhere you could use `instanceof`. (This Set will also accept subclasses of Letter.) – maraca Jul 19 '15 at 02:53
  • I think you're adding complexity, not reducing it. YAGNI. I'm trying to figure out how to fix it now, though. – durron597 Jul 19 '15 at 03:21
  • YAGNI definitely doesn't apply here because I have been needing and using this for years. It's only when I tried to combine the methods for `VFramePanel` and `VDialogPanel` into one supertype that I ran into issues. It's complex at first but once it's complete it reduces so many headaches regarding opening multiple windows, refreshing window content, etc.. – ryvantage Jul 19 '15 at 03:24
  • If the solutions to your problems are too complex, there is a very good chance it is because you are not modeling your problem domain in a way to allow for simple solutions. Elegant solutions begin with good design. – scottb Aug 29 '15 at 21:16

3 Answers3

2

I'm really not sure what you're trying to do here, but this will make your code compile:

abstract class Letter {
    public <T extends Letter> void store_object(T letter) {
        HashMap<Class<? extends Letter>, T> map = new HashMap<>();
        map.put(letter.getClass(), letter); // <-- this line throws an error
    }
}
class A extends Letter {}
class B extends Letter {}

Why are you generating a new HashMap every time the store_object method is called? What is your real problem? Please read What is the XY problem?

Related: Canonical Java Generics FAQ


By the way, Object<Anything> is always wrong because Object is not parameterized.


So I saw your edit, and FYI this compiles for me:

private static HashMap<Class<? extends Test>, Test> map = new HashMap<>();

static void addTest(Test test) {
    map.put(test.getClass(), test);
}

What's your problem exactly?

Community
  • 1
  • 1
durron597
  • 31,968
  • 17
  • 99
  • 158
  • The reason I ask about the XY problem is the real scenario is much more complex and difficult to duplicate. I'm illustrating the problem in a smaller form. It may be frustrating (thank you for the link) but when I ask problems that are close to my real problems, they go unanswered because of complexity. – ryvantage Jul 19 '15 at 03:01
  • @ryvantage Does my version (specifying the method type parameter ` void ...`) help you solve your real problem? – durron597 Jul 19 '15 at 03:02
  • Yeah, I know `Object` is wrong, I was just using it to illustrate where my head was going. Sometimes that seems to help. *shrugs* – ryvantage Jul 19 '15 at 03:22
0

Given B extends A, Class<? extends B> is not a subtype of Class<? extends A>, so using a generic bound of Class<? extends Letter> is useless.

Instead, specify the key type as simply <Class<?> and your code will compile (and you actually don't lose anything by doing this):.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
-3

It needs to be <? super Letter> instead. There's a nice acronym to help you remember PECS

If you want to use generic parameters do :

public <T extends Letter> void method(T arg1) 

**^oops there are no lower bounds (super) on type parameters

Edit: Just saw your edit. Originally I thought you were just placing objects into some collection. The static map declaration type arguments are correct. because this one instance will be used by everything for both usage and storage, so it needs to be <Class<? extends>, VCorePanel>.

static Map<Class<? extends VCorePanel>, VCorePanel> self...pm;
public static showPanel(T newInstance){
    ...
    VCorePanel OldInstance = self_panel_map.get(newInstance.getClass()); //use
    ...
    self_panel_map.put(newInstace.getClass(), newInstance); //storage
}

ps. if you are using java 8, you can just pass in a constructor as opposed to using the reflection library. look into it if you'd like.

Community
  • 1
  • 1
Aarjav
  • 1,334
  • 11
  • 22
  • Why are you suggesting `super`? – sstan Jul 19 '15 at 03:14
  • From the collection's point of view, it is 'consuming' those objects. Consumption usually means you need super. (See link above). Example: you have a List. You want to place Objects of class A into it. You can if A extends T. Meaning T super A. – Aarjav Jul 19 '15 at 03:26