我有以下代码:
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() + " ");
}
我的问题:
h.values()
返回h
中值的集合视图。由于vals
是一个接口,我们如何为接口分配一些值(它们无法实例化)?实现此接口的类在哪里?那个班级的目标在哪里?
itr
的同类问题。我们知道vals.iterator()
会返回集合的第一个元素。我们如何将它分配给接口实例?
答案 0 :(得分:2)
管理问题答案的基本原则称为Liskov's Substitution Principle,在这种情况下适用于分配给定接口实例的值(Collection
,{{1} })一个类型是实现该接口的类的引用(例如Iterator
,一些匿名类等)。
如果您看到AbstractCollection
方法代码,您将在Java 8源代码中看到:
HashMap#values()
因此,您将被退回
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(); }
...
}
类的一个实例,它扩展了实现Values
的{{1}}或AbstractCollection
中Collection
的Java AbstractCollection
中的values = new AbstractCollection<V>()
。同样,根据LSP,这一切都是有效的。要了解所有这些是如何连接起来的,您需要了解JDK代码库。
h.values()返回h的值的Collection视图。由于val是一个接口,我们如何为接口分配一些值(它们无法实例化)?
准确地说,386
不是接口,而是其实例。确实,你不能使用像AbstractMap.java
这样的vals
运算符来实例化一个接口Listener
,但根据LSP,你总是可以实例化new
的具体实现。接口并将其分配给类型为listener l = new Listener()
的变量,例如Listener
实现此接口的类在哪里?
在这种情况下,它是Listener
类或Listener listener = new SerialListener();
类,如上所示。
该班的对象在哪里?
在某些情况下,它是匿名内部类的一个实例,它在定义时被实例化。
我们知道vals.iterator()返回集合的第一个元素。
不太对劲。它返回实现Values
接口的类的实例。如果在返回的对象上调用AbstractCollection
方法时,您将获得该集合的第一个元素(假设它不为空)。
我们如何将它分配给接口实例?
这个想法是一样的。如果赋值语句左侧的变量(Iterator
符号的左侧)指的是接口,则右侧可以引用直接或间接实现该接口的对象的引用(通过继承层次结构)。