25

A friend and I are studying Java. We were looking at interfaces today and we got into a bit of an discussion about how interfaces are used.

The example code my friend showed me contained this:

IVehicle modeOfTransport1 = new Car();
IVehicle modeOfTransport2 = new Bike();

Where IVehicle is an interface that's implemented in both the car and bike classes. When defining a method that accepts IVehicle as a parameter you can use the interface methods, and when you run the code the above objects work as normal. However, this works perfectly fine when declaring the car and bike as you normally would like this:

Car modeOfTransport1 = new Car();
Bike modeOfTransport2 = new Bike();

So, my question is - why would you use the former method over the latter when declaring and instantiating the modeOfTransport objects? Does it matter?

14
  • 8
    a lot of answers have been downvoted. downvoters, care to explain why?
    – stivlo
    Commented Oct 10, 2011 at 17:40
  • 2
    @stivlo: a lot of the answers simply don't address the question.
    – Mat
    Commented Oct 10, 2011 at 17:45
  • 2
    I'll explain my downvotes: everyone here seems to launch into an explanation about polymorphism or the purpose of interfaces, which is not what the OP asked about. The OP was asking about whether to immediately cast to an interface type or defer the casting until later. Commented Oct 10, 2011 at 17:48
  • 2
    @Chris no, he wasn't. He was asking specifically "why would you use the former method over the latter". He doesn't even mention casting.
    – corsiKa
    Commented Oct 10, 2011 at 17:50
  • 2
    @Chris: What a horrible logic leap! Terrible reason to downvote. You should be ashamed. Commented Oct 10, 2011 at 18:24

11 Answers 11

12

There is a big plus on declaring them using the interface, which is what is known as "coding to an interface" instead of "coding to an implementation" which is a big Object Oriented Design (OOD) principle, this way you can declare a method like this:

public void (IVehicle myVehicle)

and this will accept any object that implements that interface, then at runtime it will call the implementation like this:

public void (IVehicle myVehicle)
{
    myVehicle.run() //This calls the implementation for that particular vehicle.
}

To answer the original question, why would you use one over the other there are several reasons:

1) Declaring them using an interface, means you can later substitute that value with any other concrete class that implements that interface, instead of being locked into that particular concrete class

2) You can take full advantage of polymorphism by declaring them using an interface, because each implementation can call the correct method at runtime.

3) You follow the OOD principle of code to an interface

3
  • 2
    I'm sorry but this doesn't answer the question at all. The poster is asking about why you would ever do IInterface var = new ConcreteClass();, not how interfaces work.
    – Mat
    Commented Oct 10, 2011 at 17:35
  • 4
    @Mat Yes I am aware of that, I am explaining that by declaring them using an interface, you are programming to an interface not an implementation, and that can be useful like on the example above. Commented Oct 10, 2011 at 17:37
  • 1
    That's not the point, OP knows about interfaces. You're not addressing anything about why you would ever want to declare a local variable as an IInterface when you know its concrete class. What you posted works exactly the same way in both scenarios the OP exposed.
    – Mat
    Commented Oct 10, 2011 at 17:41
9

It doesn't matter there.

Where it really matters is in other interfaces that need to operate on IVehicle. If they accept parameters and return values as IVehicle, then the code will be more easily extendible.

As you noted, either of these objects can be passed to a method that accepts IVehicle as a parameter.

If you had subsequent code that used Car or Bike specific operations that were used, then it would be advantageous to declare them as Car or Bike. The Car and Bike specific operations would be available for each of the relevant objects, and both would be usable (i.e. could be passed) as IVehicle.

3
  • +1 - It doesn't matter outside of the method using the IVehicle what type the variable is declared as, as long as it implements IVehicle. I think the "best" example of really seeing the power of interfaces is with dependency injection. Commented Oct 10, 2011 at 18:50
  • 1
    @Larry I believe one of the reasons it's advocated to declare them as IVehicle instead of Car or Bike is specifically to avoid having the subsequent code you mention that use Car or Bike specific operation. Such things cause great pains when refactoring to change between vehicle types because you've now placed a dependency on a particular type of vehicle. It's not just about passing in and out of methods, it's about the frame of mind you're in as a developer and whether you're writing code that is maintainable.
    – corsiKa
    Commented Oct 10, 2011 at 22:37
  • If later in the code you wanted to, for instance, swap the values stored in modeOfTransport1 and modeOfTransport2, then it would be a good thing you declared them as interface instances rather than concrete instances.
    – Ted Hopp
    Commented Sep 12, 2013 at 22:46
6

You're really asking: what reference type should I use?

Generally you want to use as general a reference type as possible that still gives you access to the behavior that you need. This means any of the interfaces or parent classes of your concrete type, rather than the concrete type itself. Of course, don't take this point too far -- for example, you certainly don't want to declare everything as an Object!

Consider these options:

Set<String> values1 = new TreeSet<String>();
TreeSet<String> values2 = new TreeSet<String>();
SortedSet<String> values3 = new TreeSet<String>();

All three are valid, but generally the first option of values1 is better because you will only be able to access the behavior of the Set interface, so later you can swap in another implementation quite easily:

Set<String> values1 = new HashSet<String>();

Beware of using the second option values2. It allows you to use specific behavior of the TreeSet implementation in such a way that swapping in a different implementation of Set becomes more difficult. This is fine as long as that's your goal. So, in your example, use a Car or Bike reference only when you need access to something that's not in the IVehicle interface. Be aware though that the following would not work:

TreeSet<String> values2 = new HashSet<String>(); // does not compile!

Still there are times when you need access to the methods that are not in the most general type. This is illustrated in the third option values3 -- the reference is more specific than Set, which allows you to rely on the behavior of SortedSet later.

TreeSet<String> values3 = new ConcurrentSkipListSet<String>();

The question about reference types applies not only where variables are declared, but also in methods where you have to specify the type of each parameter. Fortunately the "use as general a reference type as possible" rule of thumb applies to method parameters, too.

2
  • I believe this is the best answer here. The point is that when you look at the variable declaration you know exactly how it will be used in that code. Keeping types as general as possible is an analysis tool and coding guide. It's somehwat confusing to people who haven't had to decompose code written by others very often, but once it's helped you solve a problem the question becomes "Why would you ever NOT use the most general type)
    – Bill K
    Commented Aug 28, 2014 at 17:19
  • I certainly thought so, too!
    – jtoberon
    Commented Aug 28, 2014 at 20:35
5

Program to an interface rather than an implementation.

When you program to an interface you will write code that can handle any kind of Vehicle. So in the future your code, without modification, should work with Trains and Planes.

If you ignore the interface then you are stuck with CArs and Bikes, and any new Vehicles will require additional code modifications.

The principle behind this is:

Open to Extension, Closed to Modification.

2
  • 1
    I cannot imagine why this (and so many others on this thread) garnered TWO down votes. It's so clear and concise, giving exactly what information is important to developing solid code.
    – corsiKa
    Commented Oct 10, 2011 at 17:47
  • I'd love to see a useful code sample rather than buzzphrases, but this definitely does NOT deserve two downvotes. Commented Oct 10, 2011 at 17:59
3

Because you don't really care what the implementation is... only what it's behavior is.

Say you have an animal

interface Animal {
    String speak();
}

class Cat implements Animal {

    void claw(Furniture f) { /* code here */ }

    public String speak() { return "Meow!" }
}

class Dog implements Animal {

    void water(FireHydrant fh) { /* code here */ }

    public String speak() { return "Woof!"; }
}

Now you want to give your kid a pet.

Animal pet = new ...?
kid.give(pet);

And you get it back later

Animal pet = kid.getAnimal();

You wouldn't want to go

pet.claw(favorateChair);

Because you don't know if the kid had a dog or not. And you don't care. You only know that --Animals-- are allowed to speak. You know nothing about their interactions with furniture or fire hydrants. You know animals are for speaking. And it makes your daughter giggle (or not!)

kid.react(pet.speak());

With this, when you make a goldfish, the kid's reaction is pretty lame (turns out goldfishes don't speak!) But when you put in a bear, the reaction is pretty scary!

And you couldn't do this if you said

Cat cat = new Cat();

because you're limiting yourself to the abilities of a Cat.

1
  • 4
    Curious as to how this (and so many others) got so many downvotes. Seems a bit strang, to be honest.
    – corsiKa
    Commented Oct 10, 2011 at 17:46
2

Honestly your argument is rather moot. What's happening here is an implicit conversion to an IVehicle. You and your friend seem to be arguing about whether it's better to do it immediately (as per the first code listing), or later on (when you call the method, as per the second code listing). Either way, it's going to be implicitly converted to an IVehicle, so the real question is -- do you need to deal with a Car, or just a Vehicle? If all you need is an IVehicle, the first way is perfectly fine (and preferable if at a later point you want to transparently swap out a car for a bike). If you need to treat it like a car at other points in your code, then just leave it as a car.

7
  • 1
    I can't speak for the OP's friend, but I believe the idea is that developers should be avoiding "needing to treat it like a car" whenever possible. By instantiating as a Vehicle instead of a Car, you force people to think of things in terms of a Vehicle. This way, when you replace your Car with a Plane, which will most certainly happen sometime during the lifetime of your application, you have no (repeat, NO) refactoring to do.
    – corsiKa
    Commented Oct 10, 2011 at 17:54
  • 1
    To quote einstein: "Make things as simple as possible, but not simpler." Use an interface as often as you can, but believe it or not there are times when you do need to treat a car like a car. If that's the case, then an interface is not appropriate. Commented Oct 10, 2011 at 17:56
  • It's not so much an argument as trying to figure out what we're doing. My mate figured out the above code, we just want to understand the implications of each option.
    – mal
    Commented Oct 10, 2011 at 17:56
  • 1
    @Chris There are times, yes. But those times should be avoided. What advantage do you get by treating a car only like a car instead of a vehicle? If you DO have times when you are treating a car like a car instead of a vehicle, then you have likely made a mistake in your design.
    – corsiKa
    Commented Oct 10, 2011 at 17:58
  • @glowcoder: cars have engines. Bikes don't. It's tempting to say "let the object manage itself", but come on -- how often does an engine fix itself? No, a good design would still allow for the possibility of an outside object being aware of Car ojbects (perhaps a CarMechanic object). Modularity and interfaces are good, but you do still need to provision for specialization. Commented Oct 10, 2011 at 18:08
1

Declaring interfaces and instantiating them with objects allows for a powerful concept called polymorphism.

List<IVehicle> list = new ArrayList<IVehicle>();
list.add(new Car());
list.add(new Bike());

for (int i = 0; i < list.size(); ++i)
    list.get(i).doSomeVehicleAction();   // declared in IVehicle and implemented differently in Car and Bike

To explicitly answer the question: You would use an interface declaration (even when you know the concrete type) so that you can pass multiple types (that implement the same interface) to a method or collection; then the behavior common to each implementing type can be invoked no matter what the actual type is.

2
  • 1
    Okay, could somebody please explain why I am being downvoted? Commented Oct 10, 2011 at 17:57
  • I'm not one of the downvoters, but I suspect they were motivated by your last paragraph. You claim to be answering OP's question, which is why the local variables might be declared as interface objects rather than concrete objects. Your reason--so that you can pass multiple types to a method or collection--makes no sense. A variable declared as Car can be passed to a method or collection that accepts an IVehicle. There is no requirement at all that it be declared as an IVehicle.
    – Ted Hopp
    Commented Sep 13, 2013 at 2:37
1

well interfaces are behaviors and classes are their implementation so there will be several occasions later when you will program where you will only know the behaviors(interface). and to make use of it you will implement them to get benefit out of it. it is basically used to hiding implementation details from user by only telling them the behavior(interface).

1

Your intuition is correct; the type of a variable should be as specific as possible.

This is unlike method return types and parameter types; there API designers want to be a little abstract so the API can be more flexible.

Variables are not part of APIs. They are implementation details. Abstraction usually doesn't apply.

1
  • 2
    "Abstraction usually doesn't apply" -- abstraction quite often applies to local variables. It really depends on how the variables are going to be used. If, for instance, there was reason later in the code to swap the references stored in modeOfTransport1 and modeOfTransport2, then declaring them as interface instances rather than concrete instances is required.
    – Ted Hopp
    Commented Sep 12, 2013 at 22:43
1

Even in 2022, it's confusing to understand the true purpose of an interface even to a trained eye who didn't start his/her career in java.

After reading a lot of answers in various online posts, I think that an interface is just a way to not care about the implementation details of a certain activity which is being passed down to a common goal (a certain method). To make it easy, a method doesn't really care how you implement your operations but only cares about what you pass down to it.

The OP is correct in a way to ask why we couldn't just reference to the type of the concrete class than to use an interface. But, we cannot think or understand the use case of an interface in a isolated pov. Most explanation won't justify it's use unless you look at how classes like ArrayList and LinkedList are derived. Here is my simple explanation.

Class CustomerDelivery {

line 2 -> public void deliverMeMyIphone( DeliveryRoutes x //I don't care how you deliver it){
         //Just deliver to my home address.
    }
line 3 -> DeliveryRoutes a = new AmazonDelivery();
               DeliveryRoutes b = new EbayDelivery();
 
//sending IPhone using Amazon Delivery. Final act.
deliverMeMyIphone(a.route());
 
//sending IPhone using eBay Delivery. Final act
deliverMeMyIphone(b.route());
}

Interface DeliveryRoutes {

    void route(); // I dont care what route you take, and also the method which takes me as an argument won't care and that's the contract.

}
Class AmazonDelivery implements DeliveryRoutes {
   @overide route() {
           // Amazon guy takes a different route
     }
}

Class EbayDelivery implements DeliveryRoutes {
   @overide route() {
           // ebay guy takes a different route
     }
}

From the above example In line 2, just imagine to yourself what would happen if you cast the type of value x to a concrete class like AmazonDelivery and not the interface DeliveryRoutes type? or what would happen in line 3 if you change the type from the interface to AmazonDelivery type? It would be a mess. Why? because the method deliverMeMyIphone will be forced to work with only one type of delivery i.e AmazonDelivery and won't accept anything else.

Most answers confuse us with by saying Interfaces helps in multiple inheritance which is true, don't get me wrong, but it's not the only story.

1
  • 1
    Exactly, it'd about decoupling.
    – mal
    Commented Feb 6, 2022 at 13:11
-2

With "IVehicle modeOfTransport1 = new Car();", methods owned only by Car are not accessible to modeOfTransport1. I don't know the reason anyway.

5
  • 1
    This is wrong. The object that is created is still an instance of Car. The reference stored in modeOfTransport1 can be cast to a Car (if you happen to know that this particular instance of IVehicle is, in fact, a Car) and all the Car-specific instance methods are then callable.
    – Ted Hopp
    Commented Sep 12, 2013 at 22:40
  • without casting, as asked in the original question, can you call Car-specific instance methods?
    – RobinSun
    Commented Sep 13, 2013 at 0:14
  • No, not without casting, but that wasn't my point. I was criticizing your claim that OP's code will "only instantiate the methods in the interface, but not Car's own methods...They could lead to different memory usage." Perhaps it is not what you meant, but you are clearly saying that new Car() behaves (or might behave) differently depending on what's on the left side of the assignment statement, and that simply is not true.
    – Ted Hopp
    Commented Sep 13, 2013 at 2:30
  • Yea. That should be my hypothesis. That's the only possibility I can think of. I was thinking that if a car's object is instantiated, why we cannot call it own methods. Do you know how to test the memory usage for these two object creating ways? In addition, what "cast" does internally? I am a Java beginner. Thanks for your help.
    – RobinSun
    Commented Sep 13, 2013 at 21:02
  • You can use instanceof to test whether a reference can be cast to a particular class or interface. When you declare IVehicle thing = new Car(), the reason you can't call Car-specific methods is that you or, rather, the compiler doesn't know that thing happens to be a Car (even though it is) because it is not declared to be a car. However, you can use if (thing instanceof Car) { /* cast to Car and call car-specific methods */ }. Note that casting a reference variable to another type makes no changes to the referenced object itself, just to the reference.
    – Ted Hopp
    Commented Sep 15, 2013 at 2:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.