Reputation: 1058
I have a class that uses reflection to manipulate other classes:
package com.cw.cmt;
public class Container<T extends Class<?>> {
private final Class<T> clazz;
public Container(final Class<T> clazz) {
this.clazz = clazz;
System.out.println("Expensive constructor for " + this);
}
@Override
public String toString() {
return String.format("Container [clazz=%s]", clazz);
}
}
Because these are potentially expensive to construct, I want to cache them in a Map so that they are only constructed as needed:
package com.cw.cmt;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class ContainerCache {
private static final ConcurrentMap<Class<?>, Container<? extends Class<?>>> cache = new ConcurrentHashMap<>();
public static <C extends Class<?>> Container<C> getContainer(final Class<C> clazz) {
final Container<? extends Class<?>> result = cache.computeIfAbsent(clazz, k -> new Container<C>(clazz));
// it would be nice to eliminate this cast!
return (Container<C>) result;
}
}
I'm having trouble working out the correct generic syntax for invoking this getContainer method.
// The parameterized method <Class<String>>getContainer(Class<Class<String>>) of type ContainerCache
// is not applicable for the arguments (Class<String>)
ContainerCache.getContainer(String.class);
// Bound mismatch: The generic method getContainer(Class<C>) of type ContainerCache is not applicable
// for the arguments (Class<String>). The inferred type String is not a valid substitute for the bounded
// parameter <C extends Class<?>>
ContainerCache.<String>getContainer(String.class);
// The parameterized method <Class<String>>getContainer(Class<Class<String>>) of type ContainerCache
// is not applicable for the arguments (Class<String>)
ContainerCache.<Class<String>>getContainer(String.class);
Upvotes: 1
Views: 237
Reputation: 5140
I think there is a little mistake in your Container
public class Container<T extends Class<?>> {
private final Class<T> clazz;
}
So, clazz
is a Class<Class<?>>
because T extends Class<?>
.
A simple correction:
public class Container<T> {
private final Class<T> clazz;
}
and
public class ContainerCache {
private static final ConcurrentMap<Class<?>, Container<?>> cache = new ConcurrentHashMap<>();
public static <T> Container<T> getContainer(final Class<T> clazz) {
return (Container<T>) (cache.computeIfAbsent(clazz, k -> new Container<T>(clazz)));
}
}
Actually, I don't have a nice solution to avoid the cast :)
Upvotes: 0
Reputation: 328568
I don't think you can eliminate the cast because your map contains several "types" of containers so you need to cast to the correct one.
As pointed out your Container should be a Container<T>
and a few more casts in your getContainer
should do what you wanted:
public static class ContainerCache {
private static final Map<Class<?>, Container<?>> cache = new ConcurrentHashMap<>();
public static <T> Container<T> getContainer(final Class<T> clazz) {
return (Container<T>) cache.computeIfAbsent(clazz, c -> new Container<> ((Class<T>) c));
}
}
public static class Container<T> {
private final Class<T> clazz;
public Container(final Class<T> clazz) {
this.clazz = clazz;
System.out.println("Expensive constructor for " + this);
}
@Override
public String toString() {
return String.format("Container [clazz=%s]", clazz);
}
}
It's a bit ugly but I don't think you can do much better...
Upvotes: 2