简体   繁体   English

java如何知道要返回接口的哪个实现对象?

[英]How does java get to know which implementation object of interface to return?

Please be gentle while answering, I am not a java developer (or developer in General) 回答时请保持谦虚,我不是Java开发人员(或一般开发人员)

While trying xml parsing with java I came across following - 在尝试使用Java进行xml解析时,我遇到了以下问题-

NodeList nodelist = document.getElementsByTagName("item");

Herein xml dom object let me collect all objects depending on tag name I provide, but return type is an Interface called - nodelist. 在这里,xml dom对象让我根据我提供的标签名称收集所有对象,但是返回类型是一个称为-nodelist的接口。 Since interface can not be instantiated it was a bit surprising for me. 由于无法实例化接口,这令我有些惊讶。

Keeping break point and debugging the code I realized that I actually get object for class DeepNodeListImpl which implements NodeList interface. 保持断点并调试代码,我意识到我实际上为实现NodeList接口的类DeepNodeListImpl获取了对象。

How does this happen? 这是怎么发生的? How does java know to return object of "some implementation" held by my Interface "object" in the statement declared above. Java如何知道如何在上面声明的语句中返回由我的接口“ object”持有的“某些实现”的对象。

One more thing - while reading the java api I found that IIOMetadataNode implements the NodeList but my previous code snippets does not get me object of type IIOMetadataNode 还有一件事-在阅读Java API时,我发现IIOMetadataNode实现了NodeList,但是我之前的代码片段没有使我成为IIOMetadataNode类型的对象

Excellent Question. 很好的问题。

Java does not know which implementation of objects to return. Java不知道要返回对象的哪个实现。

In your question, you reference the Document class and its getElementsByTagName method. 在您的问题中,您引用Document类及其getElementsByTagName方法。 Document is an interface which means that by itself it has no implementation code. 文档是一个接口,这意味着它本身没有实现代码。

Thus whoever implements the Document interface gets to choose all the details (including which NodeList implementation to return from the getElementsByTagName method). 因此,实现Document接口的任何人都可以选择所有详细信息(包括要从getElementsByTagName方法返回的NodeList实现)。

In the code for getElementByTagName there will be something like 在getElementByTagName的代码中,会有类似

NodeList nodeList = new DeepNodeListImpl();
// do something with nodeList
return nodeList;

Java "knows" to use this type because the code for that method will explicitly choose the implementation. Java“知道”使用这种类型,因为该方法的代码将明确选择实现。

A method can always return a subclass of what it promises to return and in general any value can at runtime be a subtype of the type it is declared as. 方法总是可以返回它所承诺返回的子类,通常,任何值在运行时都可以是它声明为的类型的子类型。

The implementor of getElementsByTagName is therefore free to return something of type DeepNodeListImpl as long as it is a subtype of NodeList . 因此,getElementsByTagName的实现者可以自由返回DeepNodeListImpl类型的DeepNodeListImpl ,只要它是NodeList的子类型即可。

That's a feature of object oriented programming. 这是面向对象编程的功能。 A class can extend a base class (or implement an interface). 类可以扩展基类(或实现接口)。 The base class or the implemented interface can then be used as a "common denominator". 然后可以将基类或已实现的接口用作“公分母”。 That means: A method that returns an object of some type may actually return an object of any class derived from that type. 这意味着:返回某种类型的对象的方法实际上可以返回从该类型派生的任何类的对象。

That's what happening in your case. 这就是您的情况。 You also do not really need about the actual class being used - you can use any method provided by the interface. 您也不需要真正使用的实际类-您可以使用接口提供的任何方法。

And you shouldn't make any assumptions about the type being returned other than the interface type. 而且,除了接口类型之外,您不应对返回的类型做任何假设。 Only if you're 100% absolutely sure you may cast to the specialized type. 仅当您100%绝对确定可以转换为特殊类型时。 Example: if you did a cast to DeepNodeListImpl now, but the implementation of the XML parser was changed, you might get an exception during the cast if the implementation does not return a DeepNodeListImpl or one of the derived classes anymore. 示例:如果您现在进行了对DeepNodeListImpl ,但是XML解析器的实现已更改,则如果该实现不再返回DeepNodeListImpl或派生类之一,则可能会在DeepNodeListImpl期间遇到异常。

Here's a real life analogy. 这是现实生活中的类比。 Suppose you contract a company to send you a gardener. 假设您与一家公司签约,请您派一名园丁。

What you expect to get is a gardener who can mow your lawn and trim the hedges (the gardener interface). 您期望得到的是一个可以修剪草坪并修剪篱笆的园丁(园丁界面)。

What you get is a real person, who might be a man, woman, old or young and who might be able to do non-gardening related things like prepare dinner (implements the cook interface), but can at least mow your lawn and trim the hedges (implements the gardener interface). 您得到的是一个真实的人,可能是男人,女人,老少皆宜,并且可能会做与园艺无关的事情,例如准备晚餐(实现烹饪界面),但至少可以修剪草坪并修剪树篱(实现园丁界面)。

The company is responsible for determining which implementation you get (the company plays the role of an 'abstract factory'). 公司负责确定获得的实施方案(公司扮演“抽象工厂”的角色)。

Normally you don't care about the non-gardening related things this implementation can do. 通常,您并不关心此实现可以执行的与园艺无关的事情。

However, if you know your gardener can cook and you want your gardener to prepare your dinner then you need to cast the gardener to cook: 但是,如果您知道自己的园丁可以做饭,并且想让园丁准备晚餐,那么您需要将园丁投下厨:

Gardener gardener = AbstractFactory.getGardener();
gardener.mowLawn();
// cast 
Cook cook = (Cook) gardener;
cook.prepareDinner();

Note that this circumvents the abstraction (and thus information-hiding) offered by the AbstractFactory: you asked for a gardener and were not supposed to care about other skills. 请注意,这绕过了AbstractFactory提供的抽象(并因此隐藏了信息):您要求园丁,而不应该在意其他技能。 The result of this is that if you start using a different factory in future you might get a gardener who cannot cook, and your cast will cause a ClassCastException at runtime (your dinner might taste horrible). 这样的结果是,如果您将来开始使用其他工厂,则可能会遇到不能做饭的园丁,并且您的演员表将在运行时导致ClassCastException(您的晚餐可能会感到可怕)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM