在Java集合API中使用接口而不是具体的数据结构

在Java集合API中使用接口而不是具体的数据结构,java,collections,Java,Collections,我目前正在阅读Horstmann的《不耐烦的人的核心Java》(我推荐它,喜欢简洁的风格),我很难理解与集合API相关的一个练习。行动如下: 我鼓励您使用接口而不是具体的数据结构,例如 Map而不是TreeMap。不幸的是,这一建议仅限于此。为什么不能 您是否使用地图来表示目录? (提示:您将如何初始化它?) 尽管接口用于变量声明,但下面的代码编译和工作时没有问题。我错过了什么 Map<String, Set<Integer>> toc = new HashMap<

我目前正在阅读Horstmann的《不耐烦的人的核心Java》(我推荐它,喜欢简洁的风格),我很难理解与集合API相关的一个练习。行动如下:

我鼓励您使用接口而不是具体的数据结构,例如
Map
而不是
TreeMap
。不幸的是,这一建议仅限于此。为什么不能 您是否使用
地图
来表示目录? (提示:您将如何初始化它?)

尽管接口用于变量声明,但下面的代码编译和工作时没有问题。我错过了什么

Map<String, Set<Integer>> toc = new HashMap<>();
toc.put("element1", IntStream.of(1, 2, 3).boxed().collect(Collectors.toSet()));
toc.put("element2", IntStream.of (3, 4, 7).boxed().collect(Collectors.toSet()));
toc.forEach( (k, v) -> {
    System.out.print(k + " ");
    v.forEach(val -> System.out.print(val + " "));
    System.out.println();
} );
}
Map toc=newhashmap();
toc.put(“element1”,IntStream.of(1,2,3).boxed().collect(Collectors.toSet());
toc.put(“element2”,IntStream.of(3,4,7).boxed().collect(Collectors.toSet());
toc.forEach((k,v)->{
系统输出打印(k+“”);
v、 forEach(val->System.out.print(val+);
System.out.println();
} );
}

Map
这样的接口是继承它的所有接口和实现它的所有类的超类型。因此
TreeMap
继承自
Map
,并且由于您始终可以将属于子类型的任何引用指定给变量,因此将
TreeMap
引用指定给
Map
变量是完全可以接受的。这称为加宽参照转换 “扩展引用转换在运行时不需要特殊操作,因此在运行时也不会引发异常。它们只是以编译时可以证明正确的方式将引用视为具有其他类型。”

因此,是的,您当然可以使用
映射
来表示域模型中的某些内容,但不能直接实例化接口;必须实例化实现它的具体类型(类)。这正是你申报时所做的
Map toc=newhashmap()

作为这一原则的延伸,您可以同样轻松地编写
AbstractMap toc=newhashmap()
因为
AbstractMap
也是
HashMap
的超类型

通常,您希望为变量声明最宽的类型,该类型可以容纳在您的逻辑中工作的最大可能的子类型引用集。如果您需要一个排序的地图,那么“地图”太宽;它不强制执行分类。您必须将变量声明为
TreeMap
,或者更好地声明为
SortedMap

通常,接口是最广泛适用的类型,但如果不是,您必须考虑它


编辑:根据评论提到了SortedMap。

我与该书的作者取得了联系,他同意问题不清楚,这是为了引导读者使用通配符类型。有关工作改为:

假设您有一个类型为
Map
的方法参数,有人用
HashMap
调用您的方法。会发生什么?您可以改用什么参数类型


答案是,在这种情况下,应该使用通配符类型:
Map

使用接口类型变量来保存对子类型的引用并不是什么新鲜事,但这是问题的主题。它从一开始就是Java的一个特性,所以书的年代不是问题。@ElliottFrisch我也很困惑,因为你可以。要回答引号中的问题,您需要使用
newtreemap()
(或者
newtreemap()
如果Java 7+),初始化它,并使用
newtreeset()
(或者
newtreeset()
)创建值。我会说Horstmann是错的,但如果没有完整的上下文,他可能会有其他的意思。我认为书中的问题是试图说明一点,即可以将变量声明为接口类型,但是你不能实例化一个接口:你必须实例化一个实现该接口的类。有一个
SortedMap
接口可以用来代替
TreeMap
。你知道为什么
HashMap
不起作用吗?提示: