views:

211

answers:

5

I need the Cache class that keep the <TKey key, TValue value> pairs. And it is desirable that TKey can be any class that supports Serializable interface and TValue can be any class that supports Serializable and my own ICacheable interfaces.

There is another CacheItem class that keeps <TKey key, TValue value> pair. I want the Cache class has the void add(CacheItem cacheItem) method. Here is my code:

public class Cache<TKey extends Serializable, 
   TValue extends Serializable & ICacheable >
{
 private Map<TKey, TValue> cacheStore = 
     Collections.synchronizedMap(new HashMap<TKey, TValue>());

 public void add(TKey key, TValue value)
 {
  cacheStore.put(key, value);
 }

 public void add(CacheItem cacheItem)
 {   
  TKey key = cacheItem.getKey();
  //Do not compiles. Incompatible types. Required: TValue. Found: java.io.Serializable
  TValue value = (TValue) cacheItem.getValue();
  //I need to cast to (TValue) here to compile
  //but it gets the Unchecked cast: 'java.io.Serializable' to 'TValue'
  add(key, value);
 }
}

In another file:

public class CacheItem<TKey extends Serializable, 
  TValue extends Serializable & ICacheable>
{
 TKey key;
 TValue value;

 public TValue getValue()
 {
  return value;
 }

 public TKey getKey()
 {
  return key;
 }
}

Is there anything I could do to avoid casting? Many thanks for answers.

+1  A: 

First, you could make ICacheable extends Serializable, that would simplify your code.


Could you try to parameterize the method add's parameter?

public class Cache<TKey extends Serializable, 
   TValue extends Serializable & ICacheable >
{
 ...
 public void add(CacheItem<TKey, TValue> cacheItem)
 {   
  TKey key = cacheItem.getKey();
  TValue value = cacheItem.getValue();
  add(key, value);
 }
}


Because CacheItem is a parameterized class, most references to it should use the parameters. Otherwise, it still has unresolved types, and you are confronted to casts.

KLE
"extend", not "implement"
Bozho
@Bozho Thanks for the nice detail.
KLE
KLE, Thanks for your comment. It clears why do I need to write CacheItem<TKey, TValue> and not simply CacheItem.
Sergey
@Sergey You're welcome :-)
KLE
+2  A: 

Make your add method signature look like this :

public void add(CacheItem<TKey, TValue> cacheItem)
Bozho
This was VERY helpful answer! The problem dissolved immediately. Many many thanks to Bozho!
Sergey
+2  A: 
    public void add(CacheItem<TKey, TValue> cacheItem) {
 TKey key = cacheItem.getKey();
 TValue value = cacheItem.getValue();
 add(key, value);
}
Luno
+2  A: 

You are using the raw type on CacheItem. Try this signature:

  public void add(CacheItem<TKey, TValue> cacheItem)

That will require that the CacheItem have the same generic parameters as the Cache.

Yishai
Yishai, your comment further clears the issue for me. Thanks for the answer.
Sergey
A: 

I think you should change your class like below

public class Cache<TKey extends Serializable, 
   TValue extends Serializable & ICacheable >
{
 private Map<Serializable, Serializable> cacheStore = 
     Collections.synchronizedMap(new HashMap<Serializable, Serializable>());

 public void add(Serializable key, Serializable value)
 {
  cacheStore.put(key, value);
 }

 @SuppressWarnings("unchecked")
public void add(CacheItem cacheItem)
 {   
  Serializable key = cacheItem.getKey();
  //Do not compiles. Incompatible types. Required: TValue. Found: java.io.Serializable
  Serializable value = cacheItem.getValue();
  //I need to cast to (TValue) here to compile
  //but it gets the Unchecked cast: 'java.io.Serializable' to 'TValue'
  add(key, value);
 }

}
DKSRathore
DKSRathore, thanks for your answer, but it is a little bit not what I really want. In reality I would use the value.GetBytesUsed() method of the ICacheable interface which this variable implements: TValue value = cacheItem.getValue() ;int bytes = value.GetBytesUsed();But I need to cast in your code: Serializable value = cacheItem.getValue();int bytes = ((ICacheable)value).GetBytesUsed(); I want to avoid casting wherever it is possible.
Sergey