返回动态对象类型的通用方法

K.B*_*rad 26 java generics methods casting

也许这之前已经问了一个问题,但像往常一样提通用字第二,你获得千元解释的答案类型擦除.我通过相位去很久以前,现在知道了很多关于泛型和它们的使用,但这种情况是一个稍微更微妙的一个.

我有表示数据在电子表格,这实际上以两种格式存储的数据的单元的容器,包括:作为用于显示的字符串,而且在另一种格式,依赖于数据(存储为对象).所述细胞还保持该型之间转换的变压器,也确实为类型有效性检查(例如,检查IntegerTransformer如果字符串是有效的整数,并且如果它是返回一个整数来存储和反之亦然).

单元格本身没有输入,因为我希望能够更改格式(例如,将二级格式更改为浮点而不是整数,或更改为原始字符串),而无需使用新类型重建单元格对象.之前的尝试确实使用了泛型类型,但是一旦定义了编码变得非常庞大并且有很多反射,就无法改变类型.

问题是:如何以键入的方式从我的Cell中获取数据?我进行了实验,发现使用泛型类型可以使用方法完成,即使没有定义约束

public class Cell {
    private String stringVal;
    private Object valVal;
    private Transformer<?> trans;
    private Class<?> valClass;

    public String getStringVal(){
        return stringVal;
    }

    public boolean setStringVal(){
        //this not only set the value, but checks it with the transformer that it meets constraints and updates valVal too
    }

    public <T> T getValVal(){
        return (T) valVal;
        //This works, but I don't understand why
    }
}
Run Code Online (Sandbox Code Playgroud)

让我失望的是:那是?它不能投射任何东西,没有类型T的输入限制它匹配任何东西,实际上它并没有真正说任何地方.具有返回类型的Object除了在任何地方都给出了铸造复杂功能之外什

在我的测试中我设置了一个Double值,它存储了Double(作为一个对象),当我做了Double testdou = testCell.getValVal(); 它立即起作用,甚至没有未经检查的施法警告.但是,当我做String teststr = testCell.getValVal()时,我得到了一个ClassCastException.真的不足为奇.

我在这看到两种观点:

一:使用未定义的强制转换似乎只不过是一种将投射放在方法内而不是在返回后放在外面的一种躲避方式.从用户的角度来看它非常简洁,但是该方法的用户必须担心使用正确的调用:所有这一切都是隐藏复杂的警告和检查直到运行时,但似乎工作.

第二种观点是:我不喜欢这段代码:它不干净,它不是我在写作时自豪的代码质量.代码应该是正确的,而不仅仅是工作.错误应该被捕获并处理,并预计,即使只有expecter用户自己的接口应该是万无一失的,我总是喜欢一个灵活的通用的,可重用的技术尴尬的一关.问题是:有没有正常的方法来做到这一点?这是一种偷偷摸摸的方式来实现无类型,所有接受的ArrayList,它返回你想要的任何东西,而不是铸造?或者有什么我在这里失踪的.有些东西告诉我,我不应该相信这段代码!

也许更多的是一个比我想要的哲学问题,但我猜这就是我所要求的.

编辑:进一步测试.

我尝试了以下两个有趣的片段:

public <T> T getTypedElem() {
    T output = (T) this.typedElem;
    System.out.println(output.getClass());
    return output;
}

public <T> T getTypedElem() {
    T output = null;
    try {
        output = (T) this.typedElem;
        System.out.println(output.getClass());
    } catch (ClassCastException e) {
        System.out.println("class cast caught");
        return null;
    }
    return output;
}
Run Code Online (Sandbox Code Playgroud)

当为typedEmm分配一个double并尝试将它放入一个String时,我得到一个异常不在转换为,但在返回时,第二个代码片段不保护.getClass的输出是java.lang.Double,表明它是从typedElem动态推断的,但是编译器级别类型检查只是被强制排除.

作为辩论的注释:还有一个获取valClass的函数,这意味着可以在运行时进行可赋值性检查.

Edit2:结果

想着我已经有两个解决方案的选项后:一个轻量级的解决方案,但注释,你传递你想尝试投它作为班级为@depreciated功能,和第二的解决方案.这种方式取决于具体情况.

Dir*_*irk 20

您可以尝试输入令牌:

public <T> T getValue(Class<T> cls) {
    if (valVal == null) return null;
    else {
        if (cls.isInstance(valVal)) return cls.cast(valVal);
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

注意,这不做任何转换(即,您不能使用此方法来提取Double,如果valValFloat或的实例Integer).

你应该得到一个关于你的定义的编译器警告getValVal.这是因为剧组无法在运行时检查(Java泛型的"擦除",这实质上意味着,泛型类型参数编译后忘了工作),所以生成的代码更像是:

public Object getValVal() {
    return valVal;
}
Run Code Online (Sandbox Code Playgroud)