12

In a current problem I am having (printing a file to a physical printer in Java) I have been running through the code like a madman trying to devour any useful missed information from the javadoc of each class used.

Now, I pulled quite a bit of this code from previous questions so there was a fair bit I didn't write myself. The issue I noticed is that the code I grabbed is initializing an object, say "SimpleDoc" which implements an interface (Doc) and assigning it to that interface?!

Little Code snippet:

Doc mydoc = new SimpleDoc(textStream, flavor, null);

Now as far as I was led to understand in java we create objects. I'm familiar with inheritance, and I'm familiar with the trick of using interfaces to allow a class to "inherit" multiple super classes.

But this just isn't sticking right. You can create a class which implements an interface, that is fine with me. But what is happening here when a interface is created and an object is reduced to its interface? What am I accessing when I reference mydoc exactly?

Community
  • 1
  • 1
Alex
  • 2,405
  • 4
  • 23
  • 36
  • 2
    mydoc is a reference to an object that implements the `Doc` interface. In this situation, the interface is used to identify the methods that can be called via the mydoc reference variable. Note that the variable (mydoc) is still a reference to an object. – DwB Jan 12 '12 at 20:54

2 Answers2

13

You can not create interfaces, what you do here is you create an object mydoc of the class SimpleDoc which implements the interface Doc. Because the class implements this interface, you are allowed to handle mydoc as if it was an instance of that interface. This allows you to access all declared methods in the interface, which are implemented in the class SimpleDoc

If, for example, your Doc-Interface would look like this:

public interface Doc {
    void print();
}

and your SimpleDoc class would look like this:

public class SimpleDoc implements Doc {

    public void clear() { ... }

    @Override
    public void print() { ... }

}

... then you could only access the print()-method of you mydoc-object. But you could also say:

SimpleDoc mydoc = new SimpleDoc();

... and then you would be also able to call clear()

Eike Cochu
  • 3,249
  • 7
  • 34
  • 57
12

The trick is to realize that you're not "creating", "instantiating", or "initializing" an interface. You are simply defining a variable as being something that you know implements that interface.

You are essentially telling other programmers working on this code that for the rest of this method, you are only interested in the fact that myDoc is a Doc (i.e., something that satisfies the Doc interface). This can make programming simpler because the IDE's auto-complete will now only show you the methods that are defined by this interface, rather than everything that a SimpleDoc is capable of doing.

Imagine that in the future you want to expand your functionality so that you could have different implementations of Doc depending on some input. Rather than creating the SimpleDoc explicitly, you say:

Doc mydoc = docFactory.getByType(inputType);

The docFactory can produce any type of Doc, and this method doesn't really care what kind gets instantiated, because it's going to treat it like a Doc regardless.

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • 1
    One more huge advantage. If you decide, in the future, to use a ComplexDoc or a MySuperOptimizedDoc, you need only change the right side of one line of code. – user949300 Jan 12 '12 at 20:58
  • @user949300: Well, arguably changing the right *and left* sides of one line of code is not that much more difficult. But by programming to an interface in the first place, you don't invite developers to start calling methods on the `SimpleDoc` which couldn't be performed on every other kind of `Doc`. As you point out, this helps reduce the amount of refactoring you'd need to perform if the Doc type changes. – StriplingWarrior Jan 12 '12 at 21:02
  • Thank you, it is much clearer now! I enjoyed the overhead knowledge of how this practice helps make the use of an object more clear, that really helps flesh out why to use certain practices like this. – Alex Jan 12 '12 at 21:06
  • @Alex: If you were to call myDoc.getType(), it would still show you that you have a `SimpleDoc` while the code is being run, but for the purposes of the compiled code, you are essentially saying that this method doesn't care what kind of Object `myDoc` is as long as you can call the methods you're expecting it to have. – StriplingWarrior Jan 12 '12 at 21:07
  • Will mydoc be restricted to only having the methods of Doc? Or does it being recognized as a SimpleDoc mean it has access to all of those other methods regardless of the interface it's been assigned to. – Alex Jan 12 '12 at 21:10
  • @Alex: `mydoc` is just a *variable*, and as such it only really exists as a compile-time abstraction. Your compiled code can only call methods on it that exist on the `Doc` interface, because the compiler does not know whether it will be a SimpleDoc, a ComplexDoc, or even `null` when the method is actually run. At runtime, when you call a method, that method will be invoked on whatever object `mydoc` happens to be referencing at that point in time. (Obviously if `mydoc` references `null` at that point, you will get a NullReferenceException.) – StriplingWarrior Jan 12 '12 at 21:36
  • How do we call that concept in Java, using an interface in the declaration part? – Dr4ke the b4dass Jul 07 '22 at 20:28
  • There's not a specific term for a variable that's declared using an interface type. The general principle of restricting the interface to as little information about a target type as you need to know is called _information hiding_, and the practice of creating separate interfaces to allow different consumers to only depend on the interfaces that they care about is called _interface segregation_. – StriplingWarrior Jul 08 '22 at 15:01