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

时间:2009-07-13 20:25:16

标签: java

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

我很确定答案是肯定的。

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

9 个答案:

答案 0 :(得分:12)

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

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

   T myVar;

}

答案 1 :(得分:7)

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

建议您创建自己的界面的答案当然不是很实用,因为他们会主动禁止发送地图和可序列化的内容而不是您的特殊界面。

答案 2 :(得分:7)

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

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

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

答案 3 :(得分:5)

public interface MyMap extends Map, Serializable {
}

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

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

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

答案 4 :(得分:3)

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

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

}

答案 5 :(得分:2)

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

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

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

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

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

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

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

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

答案 6 :(得分:0)

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

另一种方法是创建一个帮助器类,并添加一个类似这样的方法:

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

答案 7 :(得分:0)

不,你几乎需要施展。

答案 8 :(得分:0)

就我而言,它只是声明具体类型而已:

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

它允许我使用Map方法(如put)并将地图传递给需要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
}

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

链接: What does it mean to “program to an interface”?