繁体   English   中英

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

[英]Java, declare variable with multiple interfaces?

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

我很确定答案是否定的。

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

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

class MyClass<T,K,V extends Serializable & Map<K,V>> {

   T myVar;

}

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

    public <T extends Map<?,?> & Serializable> void setMap(T map)

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

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

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

public interface MyMap extends Map, Serializable {
}

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

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

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

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

public interface SerializableMap<K, V> extends Map<K, V>, Serializable {

}

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

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

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

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

我已经看到了两个解决方案,一个是始终提取数组并传递它。 SDK就是这样做的。

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

具有与“method(collection,...)”匹配的签名的任何方法几乎肯定应该是该集合的成员方法,就像迭代该集合的任何循环一样。

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

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

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

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

不,你几乎需要施展。

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

    HashMap<String, String> mySerializableMap = new HashMap<>();

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

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

public interface SerializableMap<K, V> extends Map<K, V>, Serializable {
    // No new methods or anything
}

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

public class SerilizableHashMap<K, V> extends HashMap<K, V> implements SerializableMap<K, V> {
    private static final long serialVersionUID = 4302237185522279700L;
}

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

public static void main(String[] args) {
    SerializableMap<String, String> 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
}

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM