Java泛型和枚举,模板参数丢失

2024-01-30

我有一个相当复杂的结构,但它没有按预期工作。这就是我所做的:

public interface ResultServiceHolder {
    <M, ID extends Serializable, BO extends BusinessObject<M, ID>> ResultService<M, ID, BO> getService();
}

public enum ResultTypes implements ResultServiceHolder {
    RESULT_TYPE_ONE {
        @Override
        public ResultOneService getService() { //unchecked conversion?
            return serviceInitializer.getResultOneService();
        }
    },
    RESULT_TYPE_TWO {
        @Override
        public ResultTwoService getService() {  //unchecked conversion?
            return serviceInitializer.getResultTwoService();
        }
    },
    RESULT_TYPE_THREE {
        @Override
        public ResultThreeService getService() {  //unchecked conversion?
            return serviceInitializer.getResultThreeService();
        }
    };

    protected ServiceInitializer serviceInitializer;


    protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
        this.serviceInitializer = serviceInitializer;
    }

    @Component
    public static class ServiceInitializer {
        @Autowired
        private ResultOneService resultOneService;

        @Autowired
        private ResultTwoService resultTwoService;

        @Autowired
        private ResultThreeService resultThreeService;

        @PostConstruct
        public void init() {
            for(ResultTypes resultType : ResultTypes.values()) {
                resultType.setServiceInitializer(this);
            }
        }

        //getters
    }
}

目的是概括基于枚举的调用,更确切地说,只是能够迭代枚举数组。

    for(ResultServiceHolder resultServiceHolder : ResultTypes.values()) {
        if(resultServiceHolder.equals(post.getPostResultTypeCode())) {
            return resultServiceHolder.getService().createResultSearchCriteriaResponse(postId);
        }
    }

这工作得很好而且花花公子。然而,如果我说

ResultTypes.RESULT_TYPE_ONE.getService().getRepository()

那么它是一个BaseRepository<Object, Serializable>而不是一个BaseRepository<ResultTypeOne, Long>。方法resultTypeHolder.getService()回馈ResultService<M, ID, BO>,但最终变成了Object andSerializable.

我究竟做错了什么?如何保留通用参数类型?

我想补充一点,是的,我确实意识到问题出在未经检查的选角上。但服务被定义为

public interface ResultTypeOneService
    extends ResultService<ResultTypeOne, Long, ResultTypeOneBO> {
}

我不知道为什么没有推断出类型。

EDIT:从技术上讲,如果我明确推断它们,它就会起作用:

ResultTypes.RESULT_TYPE_ONE.<ResultTypeOne, Long, ResultTypeOneBO>getService().getRepository()

但它应该是自动的,为什么它不自动工作呢?我是否应该向它提供某种包含该类型的对象?为什么返回类型不足以实现这一点?

EDIT2: 的超类ResultTypeOne is

@SuppressWarnings("serial")
@EntityListeners(EntityListener.class)
@MappedSuperclass
public abstract class EntityBase implements Serializable {

但它没有映射到边界内的任何地方。

EDIT3:非常感谢@Radiodef!理论上的解决方案最终如下,并且工作得很好:

public interface ResultServiceHolder<M, ID extends Serializable, BO extends BusinessObject<M, ID>> {
    ResultService<M, ID, BO> getService();
}

public abstract class ResultTypes<M, ID extends Serializable, BO extends BusinessObject<M, ID>>
    implements ResultServiceHolder<M, ID, BO> {

    public static ResultTypes<?, ?, ?>[] values() {
        return new ResultTypes<?, ?, ?>[] {RESULT_ONE, RESULT_TWO, RESULT_THREE};
    }

    public static final ResultTypes<ResultOne, Long, ResultOneBO> RESULT_ONE = new ResultTypes<ResultOne, Long, ResultOneBO>("Result One") {
        @Override
        public ResultOneService getService() {
            return serviceInitializer.resultOneService;
        }
    };
    public static final ResultTypes<ResultTwo, Long, ResultTwoBO> RESULT_TWO = new ResultTypes<ResultTwo, Long, ResultTwoBO>("Result Two") {
        @Override
        public ResultTwoService getService() {
            return serviceInitializer.resultTwoService;
        }
    };
    public static final ResultTypes<ResultThree, Long, ResultThreeBO> RESULT_THREE = new ResultTypes<ResultThree, Long, ResultThreeBO>("Result Three") {
        @Override
        public ResultThreeService getService() {
            return serviceInitializer.resultThreeService;
        }
    };

    protected String name;

    protected ServiceInitializer serviceInitializer;

    private ResultTypes(String name) {
        this.name = name;
    }

    protected void setServiceInitializer(ServiceInitializer serviceInitializer) {
        this.serviceInitializer = serviceInitializer;
    }

    @Component
    static class ServiceInitializer {
        @Autowired
        private ResultOneService resultOneService;

        @Autowired
        private ResultTwoService resultTwoService;

        @Autowired
        private ResultThreeService resultThreeService;

        @PostConstruct
        public void init() {
            for (ResultTypes resultType : ResultTypes.values()) {
                resultType.setServiceInitializer(this);
            }
        }
    }
}

我认为由于解决方案变得很长,我会坚持使用enum方法,并接受这种界限的丧失。由于必须添加自己的内容,我失去了更多values()实施比我从执行这些界限中获得的收益要多。然而,这是一个有趣的理论练习,再次感谢您的帮助。


好的,首先您需要了解为什么您正在做的事情可能不是您认为的那样。让我们看一个更简单的例子。

interface Face {
    <T> List<T> get();
}

你所拥有的是一个通用方法,get。泛型方法的类型参数取决于调用站点提供的内容。例如这样:

Face f = ...;
// this call site dictates T to be Number
List<Number> l = f.<Number>get();

当你像这样覆盖它时

class Impl implements Face {
    @Override
    public List<String> get() { return ...; }
}

这就是你能够做(仅因为删除)但是你可能不应该。它仅允许向后兼容非通用代码。你应该听从警告而不是这样做。这样做意味着例如我仍然可以指示它返回其他内容:

Face f = new Impl();
// now I've caused heap pollution because you
// actually returned to me a List<String>
List<Number> l = f.<Number>get();

这就是存在未经检查的转换的原因。

您的意思可能是使用通用接口声明:

interface Face<T> {
    List<T> get();
}

现在的论据是T取决于对象引用的类型。

Face<Number> f = ...;
// get must return List<Number>
List<Number> l = f.get();

我们可以像这样实现它

class Impl implements Face<String> {
    @Override
    public List<String> get() { return ...; }
}

此外,您无法访问枚举上的协变返回类型。当您重写枚举常量的方法时,其类是匿名的。匿名类没有名称,不能被引用。因此,程序员无法知道其协变返回类型来使用它。此外,枚举不能声明泛型类型参数。所以你想要做的事情对于枚举来说是不可能的。

您可以使用一个类public static final模拟通用枚举的实例:

public abstract class SimEnum<T> implements Face<T> {
    public static final SimEnum<Number> A = new SimEnum<Number>() {
        @Override
        public List<Number> get() { return ...; }
    };
    public static final SimEnum<String> B = new SimEnum<String>() {
        @Override
        public List<String> get() { return ...; }
    };

    private SimEnum() {}

    public static SumEnum<?>[] values() {
        return new SimEnum<?>[] { A, B };
    }
}

否则你需要彻底改变你的想法。

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

Java泛型和枚举,模板参数丢失 的相关文章

  • 打字稿中枚举声明中的方括号的含义是什么?

    我正在浏览一个名为 Angular ngrx 项目的打字稿文件collection ts在那里 我看到声明了以下枚举常量 import Action from ngrx store import Book from models book
  • 任意通用列表的通配符

    我有一个类 MyClass 它不是通用的 包含任意 TList 并对其执行某些操作 我希望用通用 TList 替换 TList 但 MyClass 必须保持非通用 由于 Delphi 是不变的 这样的事情是行不通的 list1 TList
  • 过滤两次 Lambda Java

    我有一个清单如下 1 2 3 4 5 6 7 和 预期结果必须是 1 2 3 4 5 6 7 我知道怎么做才能到7点 我的结果 1 2 3 4 5 6 我也想知道如何输入 7 我添加了i gt i objList size 1到我的过滤器
  • 如何在 Spring 中禁用使用 @Component 注释创建 bean?

    我的项目中有一些用于重构逻辑的通用接口 它看起来大约是这样的 public interface RefactorAwareEntryPoint default boolean doRefactor if EventLogService wa
  • jQuery AJAX 调用 Java 方法

    使用 jQuery AJAX 我们可以调用特定的 JAVA 方法 例如从 Action 类 该 Java 方法返回的数据将用于填充一些 HTML 代码 请告诉我是否可以使用 jQuery 轻松完成此操作 就像在 DWR 中一样 此外 对于
  • 在接口中使用默认方法是否违反接口隔离原则?

    我正在学习 SOLID 原则 ISP 指出 客户端不应被迫依赖于他们所使用的接口 不使用 在接口中使用默认方法是否违反了这个原则 我见过类似的问题 但我在这里发布了一个示例 以便更清楚地了解我的示例是否违反了 ISP 假设我有这个例子 pu
  • Java 集合的并集或交集

    建立并集或交集的最简单方法是什么Set在 Java 中 我见过这个简单问题的一些奇怪的解决方案 例如手动迭代这两个集合 最简单的单行解决方案是这样的 set1 addAll set2 Union set1 retainAll set2 In
  • 从最终实体获取根证书和中间证书

    作为密码学的菜鸟 我每天都会偶然发现一些简单的事情 今天只是那些日子之一 我想用 bouncy castle 库验证 java 中的 smime 消息 我想我几乎已经弄清楚了 但此时的问题是 PKIXparameters 对象的构建 假设我
  • 将流转换为 IntStream

    我有一种感觉 我在这里错过了一些东西 我发现自己做了以下事情 private static int getHighestValue Map
  • 检测并缩短字符串中的所有网址

    假设我有一条字符串消息 您应该将 file zip 上传到http google com extremelylonglink zip http google com extremelylonglink zip not https stack
  • java.lang.IllegalStateException:提交响应后无法调用 sendRedirect()

    这两天我一直在尝试找出问题所在 我在这里读到我应该在代码中添加一个返回 我做到了 但我仍然得到 java lang IllegalStateException Cannot call sendRedirect after the respo
  • 内部类的构造函数引用在运行时失败并出现VerifyError

    我正在使用 lambda 为内部类构造函数创建供应商ctx gt new SpectatorSwitcher ctx IntelliJ建议我将其更改为SpectatorSwitcher new反而 SpectatorSwitcher 是我正
  • Java ResultSet 如何检查是否有结果

    结果集 http java sun com j2se 1 4 2 docs api java sql ResultSet html没有 hasNext 方法 我想检查 resultSet 是否有任何值 这是正确的方法吗 if resultS
  • 为什么 Java 8 不允许非公共默认方法?

    让我们举个例子 public interface Testerface default public String example return Hello public class Tester implements Testerface
  • Eclipse 选项卡宽度不变

    我浏览了一些与此相关的帖子 但它们似乎并不能帮助我解决我的问题 我有一个项目 其中 java 文件以 2 个空格的宽度缩进 我想将所有内容更改为 4 空格宽度 我尝试了 正确的缩进 选项 但当我将几行修改为 4 空格缩进时 它只是将所有内容
  • Android:无法使用 DbHelper 和 Contract 类将数据插入 SQLite

    public class Main2Activity extends AppCompatActivity private EditText editText1 editText2 editText3 editText4 private Bu
  • Eclipse 启动时崩溃;退出代码=13

    I am trying to work with Eclipse Helios on my x64 machine Im pretty sure now that this problem could occur with any ecli
  • 我如何在java中读取二进制数据文件

    因此 我正在为学校做一个项目 我需要读取二进制数据文件并使用它来生成角色的统计数据 例如力量和智慧 它的设置是让前 8 位组成一个统计数据 我想知道执行此操作的实际语法是什么 是不是就像读文本文件一样 这样 File file new Fi
  • 创建一个 JSON 对象以在 Spring Boot 测试中发布

    我想编写基本测试来使用 JSON 负载在 users URL 上执行 POST 请求来创建用户 我找不到如何将新对象转换为 JSON 到目前为止有这么多 这显然是错误的 但解释了目的 Test public void createUser
  • CamcorderProfile.videoCodec 返回错误值

    根据docs https developer android com reference android media CamcorderProfile html 您可以使用CamcorderProfile获取设备默认视频编解码格式 然后将其

随机推荐

  • 将参数从批处理文件传递到 sqlplus 脚本

    我正在尝试获取一个包含我每天运行的一些脚本的用户名和密码的文件 我现在有几个脚本正在使用包含我的用户名和密码的批处理文件 我的密码批处理文件如下所示 参数文件 Rem Oracle Db set odbUsername myUserName
  • 在 Flask api 中编辑传入请求正文有效负载

    我希望使基于 Flask 的 API 对所有传入的有效负载不区分大小写 而不是必须将其应用于所有 api route 函数 我想将其应用于 app before request装饰器 这样对于所有带有 json 有效负载 POST 和 PU
  • 如何使用变量名访问对象的属性?

    这有效 psISE Options DebugBackgroundColor FFC86400 这不会 attribute DebugBackgroundColor psISE Options attribute FFC86400 错误 无
  • 如何使用 CSS 使两列居中?

    我试图在我的网站上居中放置两列 但存在一些问题 每次更改的结果都是左侧位置 参见picture http i46 tinypic com 5tov7 jpg 我究竟做错了什么 这是我的 CSS body background image u
  • JavaScript 中不区分大小写的正则表达式

    我想使用 JavaScript 从 URL 中提取查询字符串 并且想对查询字符串名称进行不区分大小写的比较 这是我正在做的事情 var results new RegExp name exec window location href if
  • 如何使用 Jackson 将一个 ObjectNode 作为子节点添加到另一个 ObjectNode 中?

    我有下面的 ObjectNode handlerObjectNode gt Info Brand BrandName TOP OF THE WORLD 我有另一个以下格式的 ObjectNode fieldObjects gt Descri
  • 按下按钮时如何隐藏/显示元素?

    我正在尝试学习如何使用 Eclipse IDE 开发 Android 我现在想做的是在按下按钮时使隐藏的 TableLayout 可见 但是 我不知道需要在按钮的 OnClick 属性中放入什么内容 另外 是否有任何在线教程可以帮助我学习如
  • 重新绘制自定义标签

    React Recharts 的自定义标签不适用于条形图 http jsfiddle net xpko4e7e http jsfiddle net xpko4e7e
  • 按键合并地图

    假设我有两张地图 val a Map 1 gt one 2 gt two 3 gt three val b Map 1 gt un 2 gt deux 3 gt trois 我想按键合并这些映射 应用一些函数来收集值 在这种特殊情况下 我想
  • 在休眠中加载百万行

    如果我想在休眠中获取百万行 它会如何工作 休眠会崩溃吗 我该如何优化它 通常您不会为此使用 hibernate 如果需要执行批量操作 请使用 sql 或 hibernate 包装器进行批量操作 加载数百万条记录不可能为您的应用程序带来良好的
  • __len__ 无法返回大数字

    下面的代码 class Container def len self return 10 100 c Container print len c returns OverflowError 无法将 int 放入索引大小的整数中 我读过这个问
  • DynamoDB 在本地计算机中创建表

    我已将 DynamoDB jar 下载到本地 Windows 计算机 并能够使用下面的命令启动服务 java jar DynamoDBLocal jar dbPath 我可以使用 localhost 8000 shell 访问 Web 控制
  • 如何以矢量化方式查找特定轴上二维数组的唯一向量?

    我有一个形状数组 n t 我想将其视为一个时间序列n vectors 我想知道独特的n vector沿线存在的价值观t dimension以及相关的t indices对于每个独特的向量 我很乐意使用任何合理的平等定义 例如numpy uni
  • 如何获取单独数据集中 cte 的行计数?

    我已经找到了一种使用 CTE 和 Row Number 函数从数据库获取快速分页结果的方法 如下所示 DECLARE PageSize INT 1 DECLARE PageNumber INT 2 DECLARE Customer TABL
  • 压缩和utf8编码

    有人可以告诉我为什么我在此过程中丢失信息吗 一些 utf 8 字符似乎未解码 Biography u003clink type or Steve Blunt u0026 Marty Kelley但其他人却这样做 Name 朱敬 Creati
  • 是否可以从管道中的 sh DSL 命令捕获标准输出

    例如 var output sh echo foo echo output output 我会得到 output 0 所以 显然我得到的是退出代码而不是标准输出 是否可以将标准输出捕获到管道变量中 以便我可以获得 output foo作为我
  • 处理多个项目时.NET Core 2.0 appsettings.json 文件位置

    我正在开发一个由多个项目组成的 NET Core 2 1 103 WebAPI 应用程序 每个项目都需要有自己的 appsettings json 文件 每个项目都位于主 解决方案 文件夹内自己的子目录中 这是目录结构的简化版本 其中包含我
  • 致命错误:在 AppKernel.php 中找不到类

    我已经按照 Symfony 文档生成了一个新的 Bundle ImgBundle 但是当在浏览器中重新加载应用程序时 它无法识别该包的主类 这是我的 ImgBundle php
  • ReSharper Unit Test Runner 忽略部署项配置

    我正在使用 Resharper 6 1 对新项目进行单元测试 它似乎忽略了 local testsettings 文件的 Deployment 部分 我尝试在 ReSharper gt 选项 gt 单元测试 gt MSTest gt 使用此
  • Java泛型和枚举,模板参数丢失

    我有一个相当复杂的结构 但它没有按预期工作 这就是我所做的 public interface ResultServiceHolder