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

13,094

Solution 1

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.

Solution 2

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

Solution 3

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.

Solution 4

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.

Solution 5

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.

Share:
13,094

Related videos on Youtube

mal
Author by

mal

Updated on June 05, 2022

Comments

  • mal
    mal almost 2 years

    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?

    • Mike Christensen
      Mike Christensen over 12 years
      So what happens if you want to write a method that takes either a Car or a Bike as a parameter? Now what?
    • emeraldjava
      emeraldjava over 12 years
      can you post the methods on the IVechical interface? What happens when you want to handle a new object type ie Bus or SpaceRocket
    • stivlo
      stivlo over 12 years
      a lot of answers have been downvoted. downvoters, care to explain why?
    • Mat
      Mat over 12 years
      @stivlo: a lot of the answers simply don't address the question.
    • home
      home over 12 years
      @stivlo: Agree, too many downvotes on reasonable answers!
    • Chris Eberle
      Chris Eberle over 12 years
      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.
    • corsiKa
      corsiKa over 12 years
      @Mat 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).
    • corsiKa
      corsiKa over 12 years
      @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.
    • Mat
      Mat over 12 years
      @glowcoder: I'm just stating the probable cause. (I didn't downvote any.)
    • Chris Eberle
      Chris Eberle over 12 years
      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?"
    • corsiKa
      corsiKa over 12 years
      @Chris I don't believe that's a logical inference. The two are incredibly different.
    • Platinum Azure
      Platinum Azure over 12 years
      @Chris: What a horrible logic leap! Terrible reason to downvote. You should be ashamed.
    • jtoberon
      jtoberon over 12 years
      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.
    • mal
      mal over 12 years
      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.
  • Mat
    Mat over 12 years
    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.
  • Oscar Gomez
    Oscar Gomez over 12 years
    @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.
  • Mat
    Mat over 12 years
    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.
  • corsiKa
    corsiKa over 12 years
    Curious as to how this (and so many others) got so many downvotes. Seems a bit strang, to be honest.
  • corsiKa
    corsiKa over 12 years
    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
    corsiKa over 12 years
    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.
  • Chris Eberle
    Chris Eberle over 12 years
    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.
  • mal
    mal over 12 years
    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.
  • Platinum Azure
    Platinum Azure over 12 years
    Okay, could somebody please explain why I am being downvoted?
  • corsiKa
    corsiKa over 12 years
    @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.
  • Platinum Azure
    Platinum Azure over 12 years
    I'd love to see a useful code sample rather than buzzphrases, but this definitely does NOT deserve two downvotes.
  • Chris Eberle
    Chris Eberle over 12 years
    @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.
  • corsiKa
    corsiKa over 12 years
    @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.
  • TheCloudlessSky
    TheCloudlessSky over 12 years
    +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.
  • corsiKa
    corsiKa over 12 years
    @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.
  • Ted Hopp
    Ted Hopp over 10 years
    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
    Ted Hopp over 10 years
    "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
    Ted Hopp over 10 years
    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.
  • RobinSun
    RobinSun over 10 years
    without casting, as asked in the original question, can you call Car-specific instance methods?
  • Ted Hopp
    Ted Hopp over 10 years
    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
    Ted Hopp over 10 years
    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.
  • RobinSun
    RobinSun over 10 years
    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.
  • Ted Hopp
    Ted Hopp over 10 years
    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.
  • Bill K
    Bill K over 9 years
    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
    Bill K over 9 years
    @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).
  • Bill K
    Bill K over 9 years
    Many people have been burned by bad implementations--working with teams that abused interfaces, perhaps forcing them on every single class as part of a team requirement in a codebase that probably didn't even warrant so much structure. This causes a lot of frusteration and over-reaction. There isn't much to be done about it--they will have to gain broader experience before really getting it. In the meantime, a good answer voted down and back up to zero can be a HUGE rep gain, so don't feel too bad for the authors :)
  • jtoberon
    jtoberon over 9 years
    I certainly thought so, too!
  • Thinker-101
    Thinker-101 over 2 years
    This answer is rubbish. That's not what the OP asked.
  • mal
    mal over 2 years
    Exactly, it'd about decoupling.