简体   繁体   中英

Why can I use an interface as a type when creating a reference to an object?

I am following Oracle's online tutorial for Java and am puzzled by a particular line of code.

The full code for the example I am looking at is here: http://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html

The particular line that bothers me is in the DataStructure class' printEven() method:

DataStructureIterator iterator = this.new EvenIterator();

I don't understand why the interface DataStructureIterator is used as the type for iterator when the actual type, EvenIterator, which I tried, works just as fine and makes more sense to me:

EvenIterator iterator = this.new EvenIterator();

It only make sense if your code must have an EvenIterator .

Otherwise the more-generalized interface should be preferred, allowing you to change the underlying implementation without any further code changes.

As a (somewhat contrived) concrete example, it might make sense to use only an ArrayList to enforce constant-time indexed access; in that case you might want to avoid the more-generalized List to make sure you don't blow up the timing of your app.

Interfaces are used to abstract the essence of the implementation in a neat type, and can and even should be used as references to the implementing types. This makes client classes agnostic of the real implementing classes, making the design more robust .

The example's choice of DataStructureIterator for the type of the variable is a stylistic one. It is valid because EvenIterator is a subtype of DataStructureIterator , so that every EvenIterator is also a DataStructureIterator .

As a rule of thumb, it is usually best for variables and method parameters to be typed as generally as possible, and for method return values to be typed as specifically as possible. That affords more flexibility to your code. How general or how specific "is possible" is a judgement call you must make, based on the nature of the code and how you intend for it to be used.

The reason you can use that interface is because EvenIterator is a DataStructureIterator. You should always use interfaces when creating a reference, as you don't usually need to know the specific implementation. Interfaces define a contract that implementing classes must conform to. Using interfaces helps to minimize coupling.

Using a simple example, an Animal (interface) can run (void run() method). Then, you want to have Dog and Cat classes and both of them can run, so you implement that interface. Now, you want to keep a list of animals that can run, so you should use Animal references instead of Dog or Cat, as all you need to know is that an Animal can run, not which kind of animal are you using.

Their example code is a bit sloppy. It would have been better as:

Iterator<Integer> iterator = this.new EvenIterator();

This makes it clear that the code using the Iterator only cares that it needs an Iterator (in this case of Integer ). Experienced Java programmers often see code like that in the example and expect to find some specific reason for the code to need, in this case, DataStructureIterator . Usually the most general applicable type is clearer and makes less assumptions. For example, I habitually write:

List<V> list = new ArrayList<V>();

(Which I read as 'I need a list, it happens to be an ArrayList but that is irrelevant to the rest of the logic'.)

Joshua Bloch in his Effective Java book dedicates a whole item to this topic - "Refer to objects by their interfaces", and a part of it I would like to quote here:

If appropriate interface types exist, then parameters, return values, variables, and fields should all be declared using interface types.

...

If you get into the habit of using interfaces as types, your program will be much more flexible. If you decide that you want to switch implementations, all you have to do is change the class name in the constructor (or use a different static factory).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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