如何使用lambda确定实现通用FunctionalInterface的Bean的类型参
我有一个通用的功能界面:
还有一些bean为不同的Animal子类实现了这个接口.
现在已经为这些bean注入了一个服务类,并给出了一个Animal实例.如何确定使用正确的Feeder bean?
我试过的事情: 我最初以为我会好好使用How to get a class instance of generics type T 然后我尝试使用bean的匿名子类.然后GenericTypeResolver可以确定每个Feeder将提供的动物的特定类型.但IntelliJ正在尖叫着我应该为它创建一个lambda,其他人也会使用PetStore. 我在Feeder接口中添加了一个getAnimalClass()方法. IntelliJ停止尖叫.但它确实感觉非常笨拙. 我第一次得到一个我尚未喂食的动物实例,我尝试/捕捉使用每个候选喂食器,直到找到一个有效的.然后我记得结果以备将来使用.也觉得很笨拙. 所以我的问题: 最佳答案
简短的回答
我担心没有真正干净的方式.由于类型被删除,你需要在某处保留类型信息,并且使用getAnimalClass()的第三个建议是一种方法(但是在你的问题中你不清楚如何在以后使用它). 我个人会摆脱lambda并将一个canFeed(动物)添加到Feeder中以委派决定(而不是添加getAnimalClass()).这样,喂食者有责任知道它可以喂养什么动物. 所以类型信息将保存在Feeder类中,例如使用通过构造传递的Class实例(或者通过覆盖getAnimalClass(),如你所想的那样):
因此canFeed方法可以使用它:
这将使PetStore中的代码非常干净:
替代答案 正如您所说,存储类型信息会使其变得笨拙.然而,您可以以另一种不那么严格的方式传递类型信息,而不会使馈送器混乱,例如依赖于您注入的Spring bean的名称. 假设您在地图中注入PetStore中的所有Feeders:
现在您有一个包含进纸器名称(并隐含它的类型)和相应的进纸器的地图. canFeed方法现在只是检查子字符串:
您可以使用它从地图中获取正确的Feeder:
深潜 lambda是干净简洁的,所以如果我们想在配置中保留lambda表达式呢.我们需要类型信息,因此第一次尝试可以将canFeed方法作为默认方法添加到Feeder< T>上.接口:
当然我们不能做A == T,并且由于类型擦除,没有办法比较泛型类型A和T.通常,你引用了the trick,只有在使用泛型超类型时才有效.您提到了Spring工具箱方法,但让我们看一下Java实现:
由于我们有多个Feeder实现,其中Feeder< T>超级接口,您可能认为我们可以采用这种策略.但是,我们不能,因为我们在这里处理lambda而lambda并没有实现为匿名内部类(它们不是编译成类而是使用invokedynamic指令)而且我们放弃了输入信息. 回到绘图板,如果我们将它改为抽象类,并将其用作lambda.然而,这是不可能的,首席语言架构师Brian Goetz解释了为什么on the mailinglist:
我们可以去创建工厂方法来解决这个问题,但这又是笨拙的,让我们走得太远. 由于我们已经做到这一点,让我们把我们的lambda回来并尝试以其他方式获取类型信息. Spring的GenericTypeResolver没有带来预期的结果Animal,但是我们可以得到hacky并利用Type信息存储在字节码中的方式. 编译lambda时,编译器会插入一个指向LambdaMetafactory的动态调用指令和一个带有lambda主体的合成方法.常量池中的方法句柄包含泛型类型,因为我们的Config中的泛型是显式的.在运行时,ASM会生成一个实现功能接口的类.不幸的是,这个特定的生成类不存储通用签名,你不能使用反射来绕过擦除,因为它是使用Unsafe.defineAnonymousClass定义的.有一个a hack从Class.getConstantPool中获取信息,它使用ASM来解析和返回参数类型,但是这个hack依赖于未记录的方法和类,并且容易受到JDK中代码更改的影响.您可以自己破解它(通过粘贴来自引用的代码)或使用实现此方法的库,例如TypeTools. Other hacks也可以工作,例如向lambda添加序列化支持并尝试获取方法签名来自序列化表单的实例化接口.不幸的是,我还没有找到解决新的Spring api的类型信息的方法. 如果我们采用这种方法在我们的界面中添加默认方法,您可以保留所有代码(例如配置)和实际的Feeder-hack hack减少到:
PetStore保持干净:
所以不幸的是,没有简单的方法,我想我们可以安全地得出结论,我们检查了所有(或至少多个基本)选项. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |