以类型安全的方式编写类

时间:2015-06-11 07:50:28

标签: java generics

我想写一个类型安全的代码。以下是我尝试过的内容:

public interface ResultTronsformer<T>{
    public T tranform(T t);
}

public class BigDecimalTransformer implements ResultTRansformer<BigDecimal>{

    public BigDecimal transform(BigDecimal t){
        return t.setScale(0);
    }
}

现在我定义了类似

的Column接口
public interface Column{
    public ResultTransformer<?> getTransformer();
}

并希望在方法

中使用它
public class Report{
    private Map<Column, Object> columnValuePairs;

    public void putIntoACollection(Column c, Object columnsValue){
         ResultTransformer<?> rt = c.getTransformer();
         columnValuePairs.put(c, rt.transform(o)); //Error: Couldn't convert Object 
                                                   //to the capture of wildcard
    }
}

如何重新设计设计以达到理想的类型安全性?也许我应该在运行时进行类型检查(抛出异常)?

4 个答案:

答案 0 :(得分:2)

您可以将列视为某种具有特定类型的容器。这样,您可以在Column声明中引入泛型类型。

public interface Column<T>{
    public ResultTransformer<T> getTransformer();
}

然后,您可以按如下方式更改Report方法:

public <T> void putIntoACollection(Column<T> c, T columnsValue){
        ResultTransformer<T> rt = c.getTransformer();
        columnValuePairs.put(c, rt.transform(columnsValue)); 
}

答案 1 :(得分:1)

您可以更改Column类并使其参数化:

public interface Column<T> {
    public ResultTransformer<T> getTransformer();
}

然后你必须参数化putIntoACollection方法(不需要参数化Report):

public class Report {
    private Map<Column, Object> columnValuePairs;

    public <T> void putIntoACollection(Column<T> c, T columnsValue) {
        final ResultTransformer<T> rt = c.getTransformer();
        columnValuePairs.put(c, rt.transform(columnsValue));
    }
}

这样,您永远不需要使用捕获类型。

以下是如何使用它的示例:

private class BigDecimalColumn implements Column<BigDecimal> {
    @Override
    public ResultTransformer<BigDecimal> getTransformer() {
        return new BigDecimalTransformer();
    }
}

public static void main(String[] args) {
    final Report report = new Report();
    report.putIntoACollection(new BigDecimalColumn(), new BigDecimal("3.14"));
}

答案 2 :(得分:1)

获得变换器时,需要指定类型,因为编译器当时不知道它。

一种可能的解决方案是将类作为参数添加到Column的getTransformer中,并返回一个专门的ResultTransformer。

public interface ResultTransformer<T> {
    public T transform(T t);
}

public interface Column{
    public <T> ResultTransformer<T> getTransformer(Class<T> theClass);
}

public class Report{
   private Map<Column, Object> columnValuePairs;

   public void putIntoACollection(Column c, Object o){
       ResultTransformer<Object> rt = c.getTransformer(Object.class);
       columnValuePairs.put(c, rt.transform(o));
   }

public interface ResultTransformer<T> {
    public T transform(T t);
}

另一种方法是概括接口Column。

答案 3 :(得分:0)

我们可以放弃所有的借口,只使用该死的原始类型

     ResultTransformer rt = c.getTransformer();

更自命不凡的解决方案 -

    static <T> T transform (ResultTransformer<T> rt, Object obj)
    {
        T t = (T)obj; // unchecked cast
        return rt.transform(t);
    }


public void putIntoACollection(Column c, Object obj){
     ResultTransformer<?> rt = c.getTransformer();
     columnValuePairs.put(c, transform(rt, obj) );

}