java - 以这种方式使用泛型时,尝试重构并避免“参数不匹配,无法转换为 SomeClass”
问题描述
好的,所以开始事情并给出上下文 - 我正在重构一些旧代码,并决定采用“0 个警告,0 个 lint 警告”规则。这意味着任何警告都会使构建崩溃...
所以,我目前的问题是原始类型列表。让我发布一些代码以提供更好的上下文:
public abstract class Event implements Cloneable {
// contents of this class aren't very important
private long timestamp;
}
public interface EventObservable<T extends Event> {
List<T> pollEvents();
List<T> subscribe(EventCallback<T> callback) throws UnsupportedOperationException;
boolean unsubscribe();
// more less-significant methods
}
public abstract class AbstractEventObservable<T extends Event> implements EventObservable<T> {
// nothing very significant
}
public class SomeEventObservable extends AbstractEventObservable<SomeEvent> {
// storage, helpers, and overriding AbstractEventObservable methods
}
EventObservable
当将各种s 添加到 a时,一切正常List<EventObservable>
。我正在尝试更改它以List<EventObservable<Event>>
消除有关使用 raw-type 的警告EventObservable
。此列表仅创建并填写一次...
但是,当我更改此行时:
final List<EventObservable> list = new ArrayList<>(8);
对其中任何一个:
final List<EventObservable<Event>>
或
final List<EventObservable<? extends Event>>
或
final List<EventObservable<? super Event>>
这里的这一点是发出警报的第一件事:
private List<EventObservable<? extends Event>> getEventObservablesList(...) {
list.add(getDeviceInfoEventObservable(...)); // returns DeviceInfoEventObservable extends AbstractEventObservable<Event>
list.add(getInstalledAppsEventObservable(...)); // returns InstalledAppsEventObservable extends AbstractEventObservable<InstalledAppsEvent>
list.add(getAppInstalledEventObservable(...)); // returns AppInstalledEventObservable extends AbstractEventObservable<AppInstalledEvent>
list.add(getAppUninstalledEventObservable(...)); //returns AppUninstalledEventObservable extends AbstractEventObservable<AppUninstalledEvent>
list.add(getNetworkSwitchEventObservable(...)); //returns NetworkSwitchEventObservable implements EventObservable<NetworkSwitchEvent>
我有点想在这里应用 PECS,但在某些时候我需要生成和使用列表。我需要用不同事件的 EventObservables 来填充它,即使我EventObservable<? extends Event>
在将它们添加到列表EventObservable<? super Event>
的地方使用,并在我只是遍历列表的地方使用,在某些时候我点击了 `List<EventObservable< ? extends Event>> 不能分配给 List<EventObservable<? 超级活动>>
那么,我最好的方法是什么?
- “打破”这些泛型类,使它们都返回 Event 而不是它们的实际事件类型?这是一个相当蹩脚的解决方案,并不比抑制“原始类型”警告好多少
? extends Event
在生成的一半代码中使用,? super Event
在遍历列表的一半代码中使用丑陋的“扩展”->“超级”强制转换?- 我真的没有很多其他的想法。我仍然不明白为什么有些东西不能点击在一起,比如不能
List<EventObservable<Event>>
从一个期望 returh 的方法返回List<EventObservable<? extends Event>>
。例如,为什么不能List<String>
从想要返回 a 的方法返回 aList<Object>
。 - 只需像以前一样使用原始类型的 EventObservable 并抑制警告
欢迎任何建议。
隐含的、隐藏的问题也是“我如何在List<EventObservable<? extends Event>>
and之间架起桥梁List<EventObservable<? super Event>>
?我真的很想避免List<EventObservable<?>>
,因为不知何故,这并不比压制对我的警告更好。它们都会有不同种类的Event
s。所以这就是为什么我Event
也想出现在那里,因为EventObservable<?>
看起来它在技术上可以接受任何东西,甚至是字符串。
编辑:
我不能真正发布 MCVE,但流程是这样的:
- 初始化类创建
EventObservable
不同类型的事件。此列表仅在初始化时创建一次。 - 该列表被传递给另一个 clsas,
EventCollector
它只是保留它。 EventSubscriber
迭代EventCollector::observableList
并订阅它们中的每一个,List<EventObservable>
私下保留一个。它与 EventCollectors 的实例相同。- 定期迭代和轮询订阅列表,并将收集到的事件列表提供给序列化层以将这些事件中的每一个序列化为 JSON,然后将 JSON 提供给网络层进行发送。
代码实际上工作正常,测试通过。但它们是原始类型的,我想改变这一点,也许有<? extends Event>
一端,和<? super Event>
,类似的东西 - 或者更好。现在我想在全部打开警告后摆脱警告,我的选择是:
- 抑制警告
- 以不太理想的方式重构,因此警告消失
- 重新设计这些作品并重写它们
我不打算重新设计整个事情,并且 usingEventObservable<?>
看起来并不比抑制警告好多少,但它肯定是一个不太理想的重构,所以警告消失了。或者也许不是,我还不知道,当我将它应用到EventObservable
使用原始类型的任何地方时,我会知道的。
下面是一些代码来说明这一点:
public class Initialization class {
private List<EventObservable> observableList; //i would like to avoid rawtype here
private List<EventObservable> initList() { //similar comment applies here
List<EventObservable<Event>> list = new ArrayList()
list.add(getSomeObservable(...)); //this works fine, because SomeObservable has a Event generic type, since it returns different types of Events
list.add(getOtherObservable(...)); // this breaks down, because OtherObservable emits Event2
list.add(getYetAnotherObservable(...)); //this breaks too, because YetAnotherObservable emits Event3
return list;
}
public init() {
// unnecessary stuff
observableList = initObservableList(...); // this also breaks in different ways depending on how i declare observableList and return type of initObservableList()
// more stuff
}
private SomeObservable getSomeObservable() { ... }
private OtherObservable getOtherObservable() { /* instantiate OtherObservable */ }
private YetAnotherObservable getYetAnotherObservable() { /* same */ }
private void test() {
EventObservable<Event> bla = getOtherObservable() // works fine
EventObservable<OtherEvent> bla2 = getOtherObservable() // doesn't work, required type EventObservable<OtherEvent>, provided OtherObservable
EventObservable<OtherEvent> bla3 = new AbstractEventObservable<OtherEvent> { ... }
EventObservable<Event> test = bla3; // fails, required type EventObservable<Event>, provided EventObservable<OtherEvent>
// sanity tests just to refresh my memory on generics
List<Number> numbers;
List<? extends Number> numbers2;
List<Integer> integers = new ArrayList<Integer>();
List<Float> floats = new ArrayList<Float>();
numbers = floats; //nope, required type List<Number>, provided List<Integer>
numbers.addAll(integers); //fine
numbers.addAll(floats); //fine
numbers2 = floats;
numbers2.addAll(integers); //nope, Required Collection<? extends capture of ? extends Number>, provided List<Integer>
}
}
public class SomeObservable extends AbstractEventObservable<Event> {
// unnecessary contents
}
public class OtherObservable extends AbstractEventObservable<OtherEvent> {
// same as above
}
public class YetAnotherObservable extends AbstractEventObservable<YetAnotherEvent> {
// ditto
}
public abstract class Event { /* mentioned above */ }
public class OtherEvent extends Event { ... }
public class YetAnotherEvent extends Event { ... }
所以,我宁愿选择EventObservable<Event>
,而是列出那些很麻烦的列表。如果我开始使用,List<EventObservable<? extends Event>>
那么当我更改它的 getter 的返回类型时,我会打开一个全新的蠕虫罐 -initList()
方法。即使我<? extends Event>
在任何地方都使用(好吧,在我尝试过的一堆文件中),我最终还是遇到了一个方法返回有界通配符并被赋予另一个采用有界通配符的方法,但是它说捕获# 1 和 capture#2 可能不同。
所以我猜我不应该在任何地方返回通配符。所以现在我认为打破这 3 个 observables 并使 Event 成为它们的通用类型可能是“最简单的”。我没有聪明的主意。
解决方案
推荐阅读
- javascript - 以特定字符串为前缀的数字的正则表达式的语法
- python - 如何在训练张量流期间获取输出层值
- java - 运行 Jar 文件时出错。IllegalStateException:未设置位置
- python - 如何仅打印输出的最大值
- python - Django表单cleaned_data完全缺少一个字段
- c# - 是否有内置方法可以拒绝 fo-DICOM 服务器上的某些 SOP 类?
- javascript - 为什么UNPKG可以免费使用,如果我过度使用会怎样?
- flutter - 如何在 InheritedWidget 中调用 setState 或更新值?
- c# - 在不尝试删除文件的情况下检查 FTP 删除权限
- ios - 滚动时水平移动全景背景