将值哈希映射到集合



我有以下代码:

HashMap<Integer, String> h = new HashMap<Integer, String>();
h.put(1, "a");
h.put(2, "b");
h.put(3, "c");
h.put(4, "d");
System.out.println(h); //{1=a, 2=b, 3=c, 4=d}
Collection<String> vals = h.values();
System.out.println(vals); //[a, b, c, d]
Iterator<String> itr = vals.iterator();
while (itr.hasNext()) //a b c d 
{
System.out.print(itr.next() + " ");
}

我的问题:

  1. h.values()返回h中值的集合视图。既然vals是一个接口,我们如何为接口分配一些值(它们不能被实例化)?实现此接口的类在哪里?该类的对象在哪里?

  2. itr类似的问题.我们知道vals.iterator()返回集合的第一个元素。我们如何将其分配给接口实例?

控制问题的答案的基本原则称为 Liskov 替换原则,在这种情况下,它适用于将给定接口(CollectionIterator)的实例的值分配给一个引用,其类型是实现该接口的类(例如AbstractCollection,一些匿名类等)。

如果您看到HashMap#values()方法代码,您将在 Java 8 源代码中看到:

public Collection<V> values() {
Collection<V> vs;
return (vs = values) == null ? (values = new Values()) : vs;
}
final class Values extends AbstractCollection<V> {
public final int size()                 { return size; }
public final void clear()               { HashMap.this.clear(); }
...
}

因此,您要么被退回

  1. Values类的实例,它扩展了实现CollectionAbstractCollection,或
  2. Java 8 源代码中AbstractCollection的具体子类的实例(请参阅:values = new AbstractCollection<V>()AbstractMap.java的第386行。

同样,根据LSP的说法,这一切都是有效的。要了解这一切是如何连接的,您需要了解JDK代码库。

更多答案

h.values() 返回 h 中值的集合视图。由于 vals 是一个接口,我们如何为接口分配一些值(它们不能实例化)?

准确地说,vals不是一个接口,而是它的实例。确实,您不能像listener l = new Listener()这样的new运算符实例化接口,例如Listener,但根据 LSP,您始终可以实例化Listener接口的具体实现并将其分配给类型为Listener的变量,例如,Listener listener = new SerialListener();

实现此接口的类在哪里?

在本例中,它是Values类或AbstractCollection类,如上所示。

该类的对象在哪里?

在某些情况下,它是在其定义时实例化的匿名内部类的实例。

我们知道 vals.iterator() 返回集合的第一个元素。

不太对劲。它返回实现Iterator接口的类的实例。如果对返回的对象调用next()方法,则会获得集合的第一个元素(假设它不为空)。

我们如何将其分配给接口实例?

想法是一样的。如果赋值语句左侧(符号左侧=变量)引用接口,则右侧可以直接或间接(通过继承层次结构)引用实现该接口的对象的引用。

最新更新