在泛型方法中使用类类型参数

时间:2010-07-07 11:39:45

标签: java generics types

我有一个泛型类,旨在保留不同类型属性的值。我想提供一种类型安全的方法来设置属性值,这样就不可能为属性分配错误类型的值。

我为所有属性类型定义了一个接口:

public interface Property<T> {

} 

其中类型参数T用于指定属性值的类型。然后假设类OrderProperty实现此接口属性可以定义为

OrderProperty property1 = new OrderProperty<String>();
OrderProperty property2 = new OrderProperty<Integer>();

最初我实现了类来保存属性值,如

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);
    }

}

问题是set()方法显然不是类型安全的,因为它不考虑属性与其值类型之间的连接,所以我可以轻松地编写类似

的内容
Properties orderProperties = new Properties<OrderProperty>();
OrderProperty countProperty = new OrderProperty<Integer>();
orderProperties.set(countProperty, "1");

它会编译。

类型安全的实现将是

public <V> void set(Property<V> key, V value) {
    properties.put(key, value);
}

但当然它不会编译,因为key不是泛型类型。

我需要像

这样的东西
public <V> void set(K<V> key, V value) {
    properties.put(key, value);
}

但是这个在语法上是不正确的。

我想知道是否有办法完成我需要的工作。

3 个答案:

答案 0 :(得分:2)

您的Properties课程只能支持一种类型的财产。这可能不是你想要的,即使这样可行:

public class Properties<V, T extends Property<? extends V>> {
    public void set(T key, V value) {
      //...
    }
}

如果要支持不同类型的属性,则必须手动检查属性的有效性。原因是Java由于type erasure

  1. 使您的财产&lt; V&gt;了解它将支持的实际类型
  2. 在Properties.set方法中检查该类型
  3. 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));
        }
    
    }
    

答案 1 :(得分:1)

我的猜测是使用

public class Properties<V> {
    public void set(Property<V> key, V value) {
        properties.put(key, value);
    }
}

编辑: 好的,根据你的评论,也许这样的事情应该这样做:

public class Properties<V, T extends Property<V>> {
    public void set(T key, V value) {

    }
}

编辑2: 要实现该课程,您可以执行类似

的操作
Properties<Integer, OrderedProperty<Integer>> properties = 
    new Properties<Integer, OrderedProperty<Integer>>

答案 2 :(得分:0)

<强> EDITED 好的,对不起,我没有完全理解你的要求。在你的情况下,我以前的答案可能是无用的。既然您希望能够在Properties类中存储不同的属性,并且put(..)方法仍然是类型安全的,那么您可以使用以下内容:

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);
    }

}

在这种情况下,您只能放置与该属性类型匹配的属性和值,如下所示:

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!