当前位置: 首页 > 面试题库 >

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

滕英奕
2023-03-14
问题内容

可能是之前问过的一个问题,但是像往常一样,第二个提到“通用”一词时,您会得到一千个答案,以解释类型擦除。我很早以前就经历了这一阶段,现在对泛型及其使用有了很多了解,但是这种情况稍微有些微妙。

我有一个表示电子表格中数据单元格的容器,该容器实际上以两种格式存储数据:既作为显示字符串,也取决于数据(作为对象存储)为另一种格式。该单元格还包含一个在类型之间转换的转换器,并且还对类型进行有效性检查(例如,IntegerTransformer检查字符串是否为有效整数,以及是否返回要存储的Integer,反之亦然)。

单元格本身未键入,因为我希望能够更改格式(例如,将辅助格式更改为float而不是整数或原始字符串),而不必使用新类型重建单元格对象。先前的尝试确实使用了泛型类型,但是一旦定义就无法更改类型,编码变得非常笨重,需要进行大量反思。

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

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

让我失望的一点是:那是?它不能强制转换任何内容,没有类型T的输入会限制它匹配任何内容,实际上它在任何地方都没有真正说出任何内容。具有返回类型的Object只会使到处都有转换复杂性。

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

我对此有两种看法:

一:使用未定义的Cast
to似乎只是将转换放入方法内部而不是在其返回之后的外部方法。从用户的角度来看,这非常整洁,但是该方法的用户必须担心使用正确的调用:所有要做的就是隐藏复杂的警告和检查,直到运行时为止,但似乎可行。

第二种观点是:我不喜欢这段代码:它不干净,不是我通常以编写自己为傲的那种代码质量。代码应该正确,而不仅仅是工作。即使唯一的预期用户是我自己,也应该捕获,处理和预期错误,接口应该是万无一失的,而且我总是更喜欢灵活的通用且可重用的技术,而不是笨拙的技术。问题是:有什么正常的方法吗?这是一种偷偷摸摸的方法来实现无类型的,所有接受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;
}

当将double分配给typedElem并尝试将其放入String时,我得到的异常不是强制转换为,而是返回的异常,第二个代码段不提供保护。getClass的输出为java.lang.Double,表明这是从typedElem动态推断出来的,但是编译器级别的类型检查只是强制进行的。

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

Edit2:结果

在考虑了选项之后,我使用了两种解决方案:一种是轻量级解决方案,但是将函数注释为@depreciated,其次是在将其传递给要尝试将其转换为类的类的解决方案。这样,可以根据情况选择。


问题答案:

您可以尝试输入令牌:

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

请注意,这不会进行任何转换(即Double,如果valValFloat或的实例,则不能使用此方法提取Integer)。

顺便说一句,您应该得到关于的定义的编译器警告getValVal。这是因为,无法在运行时检查强制类型转换(Java泛型通过“擦除”工作,从本质上讲,这意味着编译后会忘记泛型类型参数),因此生成的代码更像是:

public Object getValVal() {
    return valVal;
}


 类似资料:
  • 问题内容: 这就是我想要做的。使用反射,我想获取所有方法及其返回类型(非泛型)。我一直在这样做。但是,当我遇到返回类型未知的方法时,我遇到了限制。 我如何知道方法的返回类型是否通用?我没有奢求在运行时拥有对象。我正在尝试使用Google 或使用抽象类来获取类型信息。我想关联到对象的方法。 有人认为Java不保留通用信息。在这种情况下,为什么第一次强制转换有效而第二次强制转换无效。 任何帮助表示赞赏

  • 问题内容: 我在这里多次看到类似的问题,但有一个很大的不同。 在其他问题中,返回类型将由参数确定。我想要/需要做的是通过解析后的值确定返回类型。从我收集到的信息来看,以下方法可行: 我只是想确保在我搞砸任何东西之前,它有机会工作。提前致谢。 问题答案: 你做不到 Java返回类型必须是固定的基本类型或对象类。我敢肯定,您能做的最好的事情就是返回一个包装器类型,该包装器类型具有可获取各种可能类型的值

  • 本文向大家介绍JAVA利用泛型返回类型不同的对象方法,包括了JAVA利用泛型返回类型不同的对象方法的使用技巧和注意事项,需要的朋友参考一下 有时需要在方法末尾返回类型不同的对象,而return 语句只能返回一个或一组类型一样的对象。此时就需要用到泛型。 首先先解释个概念, 元组:它是将一组对象直接打包存储于其中的一个单一对象,这个容器对象允许读取其中元素,但不能修改。 利用泛型创建元组 测试 输出

  • 问题内容: 有没有一种方法可以将对象强制转换为方法的返回值?我尝试过这种方式,但在“ instanceof”部分给出了编译时异常: 我也尝试过这个,但是它给出了运行时异常ClassCastException: 有没有一种简便的方法可以做到这一点: 编辑:我写了正确答案的工作副本: 问题答案: 您必须使用实例,因为在编译过程中会擦除通用类型。 该方法的声明是: 这也可以用于数组类型。它看起来像这样:

  • 问题内容: 我有一个模块分开的应用程序。有几个实体和CSV模块。CSV模块仅支持struct(Entity),但我想使CSV模块可与任何类型的实体一起使用。现在,它的工作方式如下:Csv模块从通道接收数据并将其严格转换为struct。我如何实现动态返回类型,因此它可以与任何类型的Entity一起使用,而不仅限于 问题答案: 快速/肮脏的解决方案: 返回接口{},但是您最终欺骗了编译器,而类型检查的

  • 问题内容: 假设我有一个超类,它定义了以下抽象方法 现在,如果我想在某些子类中覆盖它 我收到有关类型安全和未经检查的转换的警告: 类型安全:返回类型为从类型需要选中转换,以符合从类型 没有下摔倒,如果?有什么办法可以适当消除警告吗? 问题答案: 重写方法的返回类型必须是重写方法的返回类型的子类型。 不是where 的子类型。T在这里未知。 是每个子类型化规则的的子类型。 有关通配符的一些子类型化规