The use of class type parameters in generic method
I have a generic class intended to keep values for different kinds of properties. I want to provide a type-safe way to set property values, so that it is impossible to assign property a value of wrong type.
I defined an interface to be implemented for all property kinds:
public interface Property<T> {
}
where type parameter T开发者_如何学运维 is used to specify the type of property value. Then assuming the class OrderProperty
implements this interface properties can be defined like
OrderProperty property1 = new OrderProperty<String>();
OrderProperty property2 = new OrderProperty<Integer>();
Initially I implemented the class to hold property values like
public class Properties<K extends Property> {
private Map<K, Object> properties = new HashMap<K, Object>();
public <V> void set(K key, V value) {
properties.put(key, value);
}
}
The problem is that the set() method is obviously not type-safe as it does not regard the connection between property and its value type so I could easily write something like
Properties orderProperties = new Properties<OrderProperty>();
OrderProperty countProperty = new OrderProperty<Integer>();
orderProperties.set(countProperty, "1");
and it would compile.
Type-safe implementation would be
public <V> void set(Property<V> key, V value) {
properties.put(key, value);
}
but of course it will not not compile since key is not of generic type.
I need something like
public <V> void set(K<V> key, V value) {
properties.put(key, value);
}
but this one is syntactically incorrect.
I am wondering if there is any way to accomplish what I need.
Your Properties
class would be able to support only one type of property. This is probably not what you are intending, even if this would work:
public class Properties<V, T extends Property<? extends V>> {
public void set(T key, V value) {
//...
}
}
If you want to support different types of properties, then you must check the validity of your property manually. The reason for this is Java's due to type erasure:
- Make your Property<V> aware of the actual type it is going to support
- Check for that type in the Properties.set method
public interface Property<T> {
public Class<T> getPropertyType();
}
public class OrderProperty<T> extends Property<T> {
Class<T> type;
/** This constructor is required due to type erasure, otherwise the OrderType doesn't know the property type */
public OrderProperty(Class<T> type) {
this.type = type;
}
public Class<T> getPropertyType() {
return type;
}
}
public class Properties<K extends Property> {
private Map<K, Object> properties = new HashMap<K, Object>();
public <V> void set(K key, V value) {
properties.put(key, key.getPropertyType().cast(value));
}
}
My guess would be to use something as
public class Properties<V> {
public void set(Property<V> key, V value) {
properties.put(key, value);
}
}
EDIT : Ok, based on your comment, maybe something like this should do it :
public class Properties<V, T extends Property<V>> {
public void set(T key, V value) {
}
}
EDIT 2 : To instanciate that class you can do something like
Properties<Integer, OrderedProperty<Integer>> properties =
new Properties<Integer, OrderedProperty<Integer>>
EDITED
Ok, sorry about that, I didn't fully understand your requirement. In your case, my previous answer was probably pretty useless. Since you want to be able to store different properties in your Properties
class and still have the put(..)
method be type safe, you could have something like this:
public static class Properties {
private Map<Property<?>, Object> properties = new HashMap<Property<?>, Object>();
public <V> void put(Property<V> key, V value) {
properties.put(key, value);
}
@SuppressWarnings("unchecked")
public <V> V get(Property<V> key) {
return (V) properties.get(key);
}
}
In this case, you can only put a property and a value that match the type of that property, like so:
OrderProperty<String> stringProperty = new OrderProperty<String>();
OrderProperty<Integer> countProperty = new OrderProperty<Integer>();
Properties orderProperties = new Properties();
orderProperties.put(countProperty, 3);
orderProperties.put(stringProperty, "");
orderProperties.put(stringProperty, 2);//This will not compile!
精彩评论