Java,使用多个接口声明变量?

在Java中,是否可以声明其类型为多个接口的字段/变量? 例如,我需要声明一个也是SerializableMap 。 我想确保变量引用可序列化的映射。 Map接口不扩展Serializable ,但Map的大部分实现都是Serializable

我很确定答案是否定的。

跟进 :我完全了解创建一个扩展MapSerializable的新界面。 这不起作用,因为现有的实现(例如HashMap )不实现我的新接口。

没有必要像这样声明字段/变量。 特别是因为它只能测试运行时而不是编译时间。 如果传递的Map没有实现Serializable,则创建一个setter并报告错误。

建议您创建自己的界面的答案当然不是很实用,因为他们会主动禁止发送Maps和Serializable但不是您的特殊界面。

你可以用generics来做,但它不漂亮:

 class MyClass> { T myVar; } 
 public interface MyMap extends Map, Serializable { } 

将定义一个新的接口,它是MapSerializable的联合。

您显然必须提供一个合适的实现(例如MyMapImpl ),然后您可以提供MyMap类型的变量引用(或Map ,或Serializable ,具体取决于要求)。

为了解决您的问题,您无法改进行为(例如,可序列化的地图)。 您必须具有接口和一些适当的实现。

使用一些generics技巧可以做到这一点:

  public  & Serializable> void setMap(T map) 

上面的代码使用generics来强制您传递实现两个接口的映射。 但请注意,这样做的结果是,当您实际传递地图时,它们可能需要标记为可序列化或已经可序列化的地图类型。 阅读起来也相当困难。 我会记录地图必须是可序列化的并执行测试。

您可以通过创建自己的接口来实现这一点,该接口扩展了您想要的接口

 public interface SerializableMap extends Map, Serializable { } 

我投了Brian的答案,但想增加一点更高层次的想法..

如果你查看SDK,你会发现他们很少(如果有的话)传递实际的集合对象。

原因是它不是一个好主意。 collections品极不受保护。

大多数情况下,您希望在传递副本并传递副本之前制作副本,以便对集合的任何修改都不会改变其依赖于其他内容的环境。 此外,即使使用同步集合,线程也会成为一场噩梦!

我见过两个解决方案,一个是始终提取数组并传递它。 SDK就是这样做的。

另一种是总是将集合包装在父类中(我的意思是封装,而不是扩展)。 我已经养成了这个习惯,这非常值得。 它并没有真正花费任何成本,因为你还没有复制所有的收集方法(实际上你很少复制它们中的任何一个)。 事实上,你最终要做的是将“实用程序”function从分布在你代码中的其他类中移动到包装器类中,这应该是它应该放在第一位的地方。

具有与“method(collection,…)”匹配的签名的任何方法几乎肯定应该是该集合的成员方法,迭代该集合的任何循环也应如此。

我不得不时不时地抛出它,因为这是我一段时间没有得到的东西之一(因为没有人支持这个概念)。 它似乎总是有一些缺点,但已经做了一段时间,并看到它解决的问题和编码消除,我甚至无法想象自己有任何可能的缺点,这一切都很好。

如果您想继续使用现有的Map实现,则无法真正做到这一点。

另一种方法是创建一个帮助器类,并添加如下方法:

 public static Serializable serializableFromMap(Map map) { if (map instanceof Serializable) { return (Serializable)map; } throw new IllegalArgumentException("map wasn't serializable"); } 

不,你几乎需要施展。

在我的情况下,它只是为了声明具体类型:

  HashMap mySerializableMap = new HashMap<>(); 

它允许我使用Map方法(比如put )并将map传递给需要Serializable方法,而不需要转换。 当我们学会了接口编程时,并不完美,但在我所处的情况下对我来说足够好。

如果你真的坚持:正如已经指出的那样,单独声明一个组合接口并不能解决问题,因为我们已经拥有的具体类没有实现我们的组合接口,即使它们实现了我们组合的两个接口中的每一个。 不过,我用它作为第一步。 例如:

 public interface SerializableMap extends Map, Serializable { // No new methods or anything } 

下一步也是宣布一个新类:

 public class SerilizableHashMap extends HashMap implements SerializableMap { private static final long serialVersionUID = 4302237185522279700L; } 

声明此类实现组合接口,因此可以在需要其中一种类型的任何地方使用。 它扩展了一个已经分别实现每个接口的类,因此我们不需要做更多的事情。 现在我们得到了你所要求的。 使用示例:

 public static void main(String[] args) { SerializableMap myMap = new SerilizableHashMap<>(); // myMap works as a Map myMap.put("colour1", "red"); myMap.put("colour2", "green"); // myMap works as a Serializable too consumeSerializable(myMap); } public static void consumeSerializable(Serializable s) { // So something with the Serializable } 

在大多数情况下,我认为这是矫枉过正,但现在我至少将它作为一种选择。

链接: “编程到界面”是什么意思?