为了账号安全,请及时绑定邮箱和手机立即绑定

如何使Map的特化变得不可修改?

如何使Map的特化变得不可修改?

DIEA 2023-06-28 15:51:56
我目前正在通过一个中型编码示例来刷新我的 Java 知识。我有一个数据结构Map<String, String>,通常用它来初始化它new LinkedHashMap<>()以保留插入顺序。我在代码中经常使用它,并且我想摆脱声明重复。在 C++ 中,我会给地图起别名,但据我所知,在 Java 中没有别名。所以我想出了将泛型子类化的想法,如下所示:public class Attributes extends LinkedHashMap<String, String> {    public Attributes() {        super();    }    public Attributes(Map<? extends String, ? extends String> map) {        super(map);    }}到目前为止,这看起来不错,但现在我想创建它的不可修改的副本,因为属性应该是不可变/不可修改的数据结构的一部分。在我使用这个之前:Map<String, String> unmodifiableAttributes = Collections.unmodifiableMap(        new LinkedHashMap<>(attributes));这不适用于派生类,我尝试过:Attributes unmodifiableAttributes = Collections.unmodifiableMap(        new Attributes(attributes));编译器会拒绝它Incompatible types。有没有一种简单的方法来获取此类子类的不可修改(或不可变)副本?还是我的想法完全错误?我不想写一个功能齐全的装饰器,只想写几行代码。更新到目前为止,对于我想做的事情似乎还没有好的解决方案。我查看了Java Collections类的源代码,有不可修改的映射和类似集合的内部类。它们用于包装输入集合并由相应的静态方法返回。人们可以重新实现这一点,但我认为开销太大。我们对 LSP 违规进行了更多讨论,而不是原来的问题,这确实也是一个有趣的问题。
查看完整描述

2 回答

?
一只名叫tom的猫

TA贡献1906条经验 获得超2个赞

您不能使子类LinkedHashMap不可修改,因为它会违反里氏可替换性:LinkedHashMap被记录为可变的,因此所有子类也必须是可变的。

您还有一个额外的问题,即要使地图不可修改实际上需要做很多工作:您不仅有像putand之类的明显方法remove,而且还有像clearputAllputIfAbsentcomputeIfAbsent, 之类的东西computeIfPresent。然后你必须担心视图返回方法:entrySetkeySetvalues都必须返回不可修改的视图。我确信我错过了几个也需要重写的方法,但我的观点仍然是,使可变映射不可修改并不是微不足道的。

但是,您可以拥有不可修改的 Map 实现。最简单的方法是扩展AbstractMap并委托给实际的LinkedHashMap

public class Attributes extends AbstractMap<String, String> {

    private final LinkedHashMap<String, String> delegate;


    public Attributes() {

        this(Collections.emptyMap());

    }


    public Attributes(Map<? extends String, ? extends String> map) {

        this.delegate = new LinkedHashMap<>(map);

    }


    // Override the methods you need to, and that are required by AbstractMap.

    // Details of methods to override in AbstractMap are given in Javadoc.

}

但我也会质疑你的 Attributes 类是否真的需要实现像接口一样通用的东西Map- 如果你需要这种通用性,你可以直接使用 a Map。


查看完整回答
反对 回复 2023-06-28
?
倚天杖

TA贡献1828条经验 获得超3个赞

Collections.unmodifiableMap返回 aMap<K,V>所以你必须像这样使用它:

Map<String, String> unmodifiableAttributes = Collections.unmodifiableMap( 
           new Attributes(attributes)
);

并且您无法将返回的对象转换为Attributes

Attributes unmodifiableAttributes = (Attributes) Collections.unmodifiableMap(
            new Attributes(attributes)
);

因为Collections.unmodifiableMap返回实例,private static UnmodifiableMap所以你会得到一个ClassCastException. 并且Attributes不是 的子类型UnmodifiableMap

LinkedHashMap另外,我认为在您的情况下,直接使用而不是从中创建派生类会更容易,因为据我所知,功能与原始类没有什么不同。Collections.unmodifiableMap然后使用从as返回的对象Map


查看完整回答
反对 回复 2023-06-28
  • 2 回答
  • 0 关注
  • 144 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信