Java 以类型安全的方式编写类

Java 以类型安全的方式编写类,java,generics,Java,Generics,我想写一个类型安全代码。以下是我尝试过的: public interface ResultTronsformer<T>{ public T tranform(T t); } public class BigDecimalTransformer implements ResultTRansformer<BigDecimal>{ public BigDecimal transform(BigDecimal t){ return t.setS

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

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

public class BigDecimalTransformer implements ResultTRansformer<BigDecimal>{

    public BigDecimal transform(BigDecimal t){
        return t.setScale(0);
    }
}
公共接口结果转换器{
公共T变换(T);
}
公共类BigDecimalTransformer实现ResultTRansformer{
公共BigDecimal转换(BigDecimal t){
返回t.setScale(0);
}
}
现在我定义了列接口,如下所示

public interface Column{
    public ResultTransformer<?> getTransformer();
}
公共接口列{
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
    }
}
公共类报告{
私有地图对;
public void putinoacollection(c列,Object列值){
结果Transformer rt=c.getTransformer();
columnValuePairs.put(c,rt.transform(o));//错误:无法转换对象
//捕获通配符
}
}

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

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

public interface Column<T> {
    public ResultTransformer<T> getTransformer();
}
这样,您就不需要使用捕获类型

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

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"));
}
私有类BigDecimalColumn实现列{
@凌驾
公共结果变压器getTransformer(){
返回新的BigDecimalTransformer();
}
}
公共静态void main(字符串[]args){
最终报告=新报告();
report.putinoacollection(新的BigDecimalColumn(),新的BigDecimal(“3.14”);
}

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

一种可能的解决方案是将类作为参数添加到列的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);
}
公共接口结果变压器{
公共T变换;
}
公共界面栏{
公共结果变压器getTransformer(类);
}
公开课报告{
私有地图对;
公共无效PutinoaCollection(c列,对象o){
结果Transformer rt=c.getTransformer(Object.class);
columnValuePairs.put(c,rt.transform(o));
}
公共接口结果变压器{
公共T变换;
}

另一种方法是泛化接口列。

您可以将该列视为一种保存特定类型的容器。这样,您可以在列声明中引入泛型类型

公共接口列{
public ResultTransformer getTransformer();
}
然后,您可以按如下方式更改报告方法:

public void putinoacollection(c列、T列值){
结果Transformer rt=c.getTransformer();
put(c,rt.transform(columnsValue));
}

我们可以放弃一切伪装,只需使用该死的原始类型

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

}
静态T变换(结果变换器rt,对象obj)
{
T=(T)obj;//未选中强制转换
返回rt.transform(t);
}
公共无效PutinoaCollection(c列,对象对象){
结果Transformer rt=c.getTransformer();
put(c,transform(rt,obj));
}

Java的类型系统不够强大,无法做到这一点。但您可以使用一些公开外部安全API的包装器库。例如:@Max Intersting,还没有听说过这种方法。也许您可以提供一个asnwer示例?但您认为我如何实现列接口?例如,我需要
bigdecime列
,它又是
结果变压器
的子类。我们将得到一个编译器未经检查的警告。@user3663882这个问题将不可能以不产生警告的方式解决。唯一要做的是编写可证明的类型安全代码并添加
@SuppressWarning(“未经检查”)
。再说一次,列接口的实现将是不安全的。或者我不理解某些东西……?您也可以将列接口泛化为列,但这会将列的类型参数绑定到ResultTransformer的结果,这不是我将选择的依赖项。将来,您可能希望进行多重转换对于一个列,这将不再可能。这取决于哪个类将承担定义转换器返回类型的责任。如果是列,则生成列。如果是ResultTransformer,则这是一个好方法。欢迎使用stackoverflow-这是一个很棒的第一篇文章!请注意。这并不能解决问题,因为se您只能插入一种类型的列。问题的实质是列存储不同的类型。我现在不知道此报告功能的整个上下文,但我知道列是一个包含一些值的容器。您可以为每个支持的类型创建任意数量的列。列中的值可以通过引用进行转换ResultTransformer。此ResultTransformer作为类型安全组件,应在列存储的相同类型的数据上操作。如果您有任何类型层次结构,则可以扩展单个ResultTransformer以在同一层次结构级别上操作多个类型。
    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) );

}