0

My question is does it possible to write such a class:

public class Storage{
    protected Map<String, ? extends Serializable> properties = new HashMap<>();

    public <T extends Serializable> void put(String name , T value){
        properties.put(name, value);
    }
}

and when try to use it like this:

Storage s = new Storage();
List<String> list = new ArrayList<>();
s.put("name", list);

Through code above seems legit to me, it does not compile. I was looking into generics FAQ but can't find a solution, maybe it's not possible at all?

Here is compilation error

Error: where T is a type-variable: T extends Serializable declared
in method <T>put(String,T) where CAP#1 is a fresh type-variable: CAP#1
extends Serializable from capture of ? extends Serializable
Sergey Lysenko
  • 100
  • 1
  • 7
  • 3
    If you're going to say that something doesn't compile, unexpectedly, you should *always* give the error you're seeing. – Jon Skeet Apr 08 '15 at 06:13
  • Sorry for the ambiguously, the error were Error: where T is a type-variable: T extends Serializable declared in method put(String,T) where CAP#1 is a fresh type-variable: CAP#1 extends Serializable from capture of ? extends Serializable – Sergey Lysenko Apr 08 '15 at 07:00
  • Please edit that into the *question* rather than just comments. – Jon Skeet Apr 08 '15 at 08:32
  • the method declaration could just be written as `public void put(String name , Serializable value)` – user102008 Apr 08 '15 at 19:44

2 Answers2

3

You should have a look at PECS( Producer extends Consumer Super ) concept. You cannot add anything to ? extends Serializable. You can only read from it. If you want to add instances of type T to a collection then use ? super T (it acts as consumer i.e, accepts values).

TheLostMind
  • 34,842
  • 11
  • 64
  • 97
  • 1
    A great answer that I think explains `PECS` very well can be found on [this SO question](http://stackoverflow.com/a/4343547/627727). – mkobit Apr 08 '15 at 06:23
  • How PECS related to this question? It is a great concept at overall, but can't be applied here. How can you say what class must implement Serializable marker interface using super T>? Fortiori, i think we can't use super in method declaration. – Sergey Lysenko Apr 08 '15 at 06:42
  • @SergeyLysenko - You have declared that your map only accepts `? extends Serializable` as values.. and you are trying to add values to it. According to PECS, you cannot add anything to it. `properties.put(name, value);` will give you an error :) – TheLostMind Apr 08 '15 at 06:45
2

You could do the following:

public class Storage{
    protected Map<String, Serializable> properties = new HashMap<>();

    public <T extends Serializable> void put(String name , T value){
        properties.put(name, value);
    }
}

Note that the List Interface does not extend Serializable:

Storage s = new Storage();
ArrayList<String> list = new ArrayList<>();
s.put("name", list);
DSF
  • 786
  • 6
  • 15
  • Maybe i get it complete wrong but the concrete class ArrayList implements serializable, does i need to cast List to Array List before calling put method? – Sergey Lysenko Apr 08 '15 at 06:31
  • Yes, you can do that but it's more easily to just use the ArrayList :) – DSF Apr 08 '15 at 06:32
  • Thanks for solving this concrete problem, changing the Map generic declaration solves it in general way, but not my case. Generics check the references types instead of types of concrete classes. So i thing i should use the instanseof check instead of generic method declaration. Thanks anyway. – Sergey Lysenko Apr 08 '15 at 07:05