Why would you declare an Interface and then instantiate an object with it in Java?
Asked Answered
K

11

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?

Karyolysis answered 10/10, 2011 at 17:29 Comment(14)
So what happens if you want to write a method that takes either a Car or a Bike as a parameter? Now what?Boob
can you post the methods on the IVechical interface? What happens when you want to handle a new object type ie Bus or SpaceRocketVitals
a lot of answers have been downvoted. downvoters, care to explain why?Sanjuana
@stivlo: a lot of the answers simply don't address the question.Kumiss
@stivlo: Agree, too many downvotes on reasonable answers!Funnelform
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.Chan
@Kumiss 7 of 10 answers received 2 downvotes. Of the ones that did, most did address the question. In any case, I would hardly describe them as not useful (the stated criteria for downvote).Bakunin
@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.Bakunin
@glowcoder: I'm just stating the probable cause. (I didn't downvote any.)Kumiss
The OP wasn't asking why use an interface over a concrete type. The OP was asking, "why define the variables this way instead of that way", which to me is the same as asking, "implicit cast now, or later?"Chan
@Chris I don't believe that's a logical inference. The two are incredibly different.Bakunin
@Chris: What a horrible logic leap! Terrible reason to downvote. You should be ashamed.Perpetuity
I'm curious to see which answer is accepted! I agree that being potentially off topic is not a reason for a down vote, as long as the answer itself is accurate.Caterpillar
Thanks Everyone, these answers and discussion helped a lot, I marked the correct one based On the higher voting. Aside from that I couldn't decide between Larry Watanabe or Oscar Gomez posts. I agree that some of the answers seem to have been unnecessarily down voted. Thanks again.Karyolysis
A
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.

Attorney answered 10/10, 2011 at 17:34 Comment(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.Attached
@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.Bakunin
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.Recur
G
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

Gillespie answered 10/10, 2011 at 17:32 Comment(3)
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.Kumiss
@Kumiss 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.Gillespie
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.Kumiss
A
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.

Attorney answered 10/10, 2011 at 17:34 Comment(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.Attached
@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.Bakunin
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.Recur
C
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.

Caterpillar answered 10/10, 2011 at 17:36 Comment(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)Capriole
I certainly thought so, too!Caterpillar
S
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.

Stafford answered 10/10, 2011 at 17:32 Comment(2)
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.Bakunin
I'd love to see a useful code sample rather than buzzphrases, but this definitely does NOT deserve two downvotes.Perpetuity
B
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.

Bakunin answered 10/10, 2011 at 17:31 Comment(1)
Curious as to how this (and so many others) got so many downvotes. Seems a bit strang, to be honest.Bakunin
C
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.

Chan answered 10/10, 2011 at 17:44 Comment(7)
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.Bakunin
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.Chan
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.Karyolysis
@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.Bakunin
@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.Chan
@Chris No, they don't really. When was the last time you HAD to make a method take a HashSet instead of a Set? Never. Why? Because it was well designed. Modularity and interfaces are good, and specialization is indicative of a primitive understanding of the problem.Bakunin
@Chris according to your design, Car and Plane should have completely different copy and paste implementations. The problem is that you didn't creat a "Engined" interface as well as Vehicle (Assuming you didn't want to just put a hasEngine() method on your vehicle, another reasonable solution).Capriole
P
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.

Perpetuity answered 10/10, 2011 at 17:33 Comment(2)
Okay, could somebody please explain why I am being downvoted?Perpetuity
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.Recur
P
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).

Piegari answered 10/10, 2011 at 18:36 Comment(0)
C
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.

Connate answered 11/10, 2011 at 2:42 Comment(1)
"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.Recur
P
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.

Patronage answered 6/2, 2022 at 12:50 Comment(1)
Exactly, it'd about decoupling.Karyolysis
T
-2

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

Threnody answered 12/9, 2013 at 22:19 Comment(5)
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.Recur
without casting, as asked in the original question, can you call Car-specific instance methods?Threnody
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.Recur
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.Threnody
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.Recur

© 2022 - 2024 — McMap. All rights reserved.