Reputation: 508
First of all, I'm not an expert of generics, but I attempted to create a class to persist any type of object into a specified path using the following approach.
public class PersistentObject<T> {
/**
* Persisted object class.
*/
private Class<T> clazz;
/**
* Persisted object.
*/
private T object;
/**
* Path of the file where the object is persisted
*/
private String path;
public PersistentObject(String path, Class<T> clazz) {
this.clazz = clazz;
this.path = path;
load(); //Load from file or instantiate new object
}
}
It works fine, but I'm not able to use T
as a class that implement the interface Map<K, V>
, mainly because of the clazz
constructor parameter. Here is what I'm trying to achieve:
PersistentObject<String> test =
new PersistentObject<String>("path", String.class);
PersistentObject<HashMap<String, Integer>> test2 =
new PersistentObject<HashMap<String, Integer>>("path", HashMap<String, Integer>.class); // Compilation error
The problem is how can I pass a Class
object that allows the instantiation of a HashMap<K, V>
, e.g. HashMap<String, Integer>
, if there is one?
I guess there is a design flaw in my implementation, some misunderstanding of generics concepts, or both. Any comments or suggestions are really welcome.
Thanks in advance.
Upvotes: 2
Views: 763
Reputation: 3288
import java.util.*;
public class PersistentObject<T> {
/**
* Persisted object class.
*/
private Class<T> clazz;
/**
* Persisted object.
*/
private T object;
/**
* Path of the file where the object is persisted
*/
private String path;
public PersistentObject(String path, Class<T> clazz) {
this.clazz = clazz;
this.path = path;
//load(); //Load from file or instantiate new object
}
public static void main(String... args) {
PersistentObject<String> test =
new PersistentObject<String>("path", String.class);
PersistentObject<HashMap<String, Integer>> test2 = new PersistentObject<>("path", (Class<HashMap<String, Integer>>) (Class<?>) HashMap.class);
}
}
Upvotes: 1
Reputation: 178263
You are using a class literal to pass a Class
object into your PersistentObject
constructor. However, generics aren't supported in class literals, because in Java generics is a compile-time feature. Due to type erasure, the generic type parameters aren't available at runtime, presumably when you plan to use this Class
object.
Assuming that you need the Class
object to instantiate a HashMap
at runtime, the type information isn't available to create a HashMap<String, Integer>
-- only a HashMap
.
To get it to compile, you can use an unchecked cast.
PersistentObject<HashMap<String, Integer>> test2 =
new PersistentObject<>("path",
(Class<HashMap<String, Integer>>) (Class<?>) HashMap.class);
Casting to Class<?>
from a class literal is allowed without a warning, but you'll get a compilation warning about casting that to a Class<HashMap<String, Integer>>
. You can use @SuppressWarnings("unchecked")
to remove the warning. Just be sure that this unchecked cast is indeed safe for your purposes.
Upvotes: 2