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

2024-03-22

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

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

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

问题是:如何以类型化方式从 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
    }
}

让我失望的是:那是?它不能投射任何东西,没有类型 T 的输入限制它匹配任何东西,实际上它在任何地方都没有说什么。拥有 Object 的返回类型没有任何作用,只会使各处的转换变得复杂。

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

对此我看到有两种观点:

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

第二种观点是:我不喜欢这段代码:它不干净,它不是我通常为自己编写的代码质量而自豪的。代码应该是正确的,而不仅仅是工作。错误应该被捕获和处理,并且预期,界面应该是万无一失的,即使唯一的预期用户是我自己,而且我总是更喜欢灵活的通用和可重用的技术,而不是尴尬的一次性技术。问题是:有什么正常的方法可以做到这一点吗?这是实现无类型、全部接受 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 的函数,这意味着可以在运行时进行可分配性检查。

编辑2:结果

在考虑了这些选项之后,我采用了两种解决方案:一种是轻量级解决方案,但将函数注释为@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, if valVal是一个实例Float or Integer).

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

public Object getValVal() {
    return valVal;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

返回动态对象类型的通用方法 的相关文章

随机推荐

  • 透明 jQuery UI 对话框

    有人知道如何使 ui 对话框透明吗 创建一个类 transparent class filter alpha opacity 50 for IE4 IE7 ms filter progid DXImageTransform Microsof
  • 如何在 HTML 中制作选项卡式视图?

    单击选项卡 A 时 显示选项卡 A 的内容 单击选项卡 B 时 显示选项卡 B 的内容 依此类推 构建 HTML 片段最简单且兼容的方法是什么 我不想在这里使用任何库 所以没有jQuery http en wikipedia org wik
  • 使用 glTexImage2D 的奇怪结果

    我一直在试图弄清楚如何glTexImage2D有效 并且从一些非常清晰的代码中看到一些奇怪的结果 我的代码只是将一个粗略的圆绘制到一个 256 256 长度的无符号数组中 然后将该数据发送出去以成为纹理 然而 无论我在图像创建循环中选择什么
  • 根据时间在 perl 脚本中运行子程序?

    我有一个 perl 脚本 它作为守护进程一直循环运行 我想在基于时间 或计时器 的 perl 脚本中运行一个子函数 因此每 2 小时它将运行该子函数并继续其循环 我正在考虑获取纪元时间 然后通过循环检查几次 一旦它大于 2 小时 它就会运行
  • 仅当 EntityCollection 或 EntityReference 不包含对象时才能调用 Load

    正如标题所示 当我使用实体框架 4 1 的延迟加载来关闭跟踪时 我收到了错误 完整的异常消息 当使用 NoTracking 合并选项返回对象时 仅当 EntityCollection 或 EntityReference 不包含对象时才能调用
  • Joda 时间 两个日期之间的时间间隔(包括时区)

    我使用 JodaTime 库进行时间操作 我有两个日期 日期一 DateTime time server new DateTime server time milisecs withZone DateTimeZone forID Europ
  • Devise 令牌身份验证错误:未设置 Devise.secret_key

    我目前正在使用 Devise 令牌身份验证 https github com lynndylanhurley devise token auth https github com lynndylanhurley devise token a
  • 如何隐藏“网络”选项卡中的请求

    如何在浏览器开发者工具的网络选项卡中隐藏 api 服务请求 任何建议 尽管我强烈建议不要这样做 因为它不会阻止任何认真的用户 但是可以通过 flash 或任何其他具有此类功能的插件来发送它 实现这一目标的最简单方法是使用启用 Flash 的
  • Paramiko - 在“后台”运行命令

    我已经使用 exec command 成功实现了 Paramiko 但是 我在远程计算机上运行的命令有时可能需要几分钟才能完成 在此期间 我的 Python 脚本必须等待远程命令完成并接收标准输出 我的目标是让远程机器 在后台运行 并允许本
  • Angular 下载大 blob

    我有一个类似的问题this one https stackoverflow com questions 46932213 how to download large file with javascript我成功下载了通过 HTTP GET
  • Objective-C:Unicode 日期格式

    我正在尝试找出如何使用 UNICODE 表示 Sun 03 May 2009 19 58 58 0700 as eee dd MMM yyyy HH mm s ZZZZ 或其他 我似乎无法让它精确地工作 Use an NSDateForma
  • 字符编码问题?

    在我的 mysql 数据库中 页面名称字段中有以下信息 如果我执行 phpmyadmin 转储 则会导出以上内容 我正在使用不同的 php 脚本 而不是上面的脚本 我得到的是这个 这是生成输出的片段 data sql SELECT FROM
  • SQL 存储过程 - 从多个数据库执行

    我的公司使用来自许多客户的数据 并且忽略了记录我们数据库的表和字段所代表的内容 为了帮助解决这个问题 我编写了一些存储过程 这些过程似乎只适用于它们所在的数据库 我希望服务器上有一个存储过程实例 可以在其所有数据库上使用 但不知道如何实现这
  • 在 Idea 中查找对某个对象的所有引用

    Intellij IDEA IDE 是否有快捷键或选项来查找对某个文件的所有引用Class在一个特定的项目中 例如 我创建了自己的Class持有一个String and an int我已经通过该项目进行了参考 该项目相当大 我不想手动搜索每
  • 有没有办法将 python 应用程序编译成静态二进制文件?

    我想做的是将我的代码发送到远程服务器 该服务器可能安装了不同的 python 版本和 或可能没有我的应用程序所需的包 现在为了实现这种可移植性 我必须使用解释器和代码构建可重定位的 virtualenv 这种方法有一些问题 例如 您必须手动
  • [Vue warn]:$attrs 是只读的。 [Vue 警告]:$listeners 是只读的

    我对 Vuejs 比较陌生 每次按下按键时都会收到以下警告 Vue warn attrs is readonly found in gt
  • 用于从 const 映射中读取的惯用 C++

    For an std map
  • Canny Edge 之后的边界检测

    我尝试过 Canny Edge 的开源 Java 实现 我只需要图像的边界 轮廓 但输出中有额外的线条 使用 Canny Edge 后有什么方法可以删除这些线条 是否有其他算法 或者是否有其他方法可以修改程序 使其仅检测轮廓 我试过了thi
  • WSO2 API 管理器端口

    我需要发布为在端口 80 和 443 而不是 8280 和 8243 上运行而开发的所有 API 我如下更改了 axis2 xml 并重新启动了 API Manager 服务器
  • 返回动态对象类型的通用方法

    可能是一个以前被问过的问题 但像往常一样 当你提到通用这个词时 你会得到一千个解释类型擦除的答案 我很久以前就经历过这个阶段 现在对泛型及其使用有了很多了解 但这种情况稍微微妙一些 我有一个代表电子表格中数据单元格的容器 它实际上以两种格式