Is co-variance safe here? - java

class Food{}
class Meat extends Food{}
class Animal{
void feed(Food f){}
}
class Lion extends Animal{
void feed(Meat m){}
}
void foo(Animal a){
Food f = new Food();
a.feed(f);
}
What will happen if we send to foo(new Lion()) ?
I know that it will get error but I need the explanation please

Your Lion can eat Meat, but it can also eat any kind of food (like Spinach).
If your Lion could not eat any kind of Food, then it could not be considered an implementation of Animal.
This is critical to understand when deciding to use sub-classing and class inheritance as a means of constructing programs: you don't make your subclasses more specific than your interface or super classes.
For sub-classing to work in ways that solve problems (instead of create problems), you need to abide by this guideline: All subclasses must be functionally equivalent to the super-class (Liskov Substitution Principle) This means that three classes which provide database access to three different databases is a good candidate for being subclasses from a common class (or perhaps sharing a common interface), because the "functionality" is "offer database access".
Where your Lion example falls short is that according to your definition of Animal a real world, Lions are not an Animals because real world Lions don't eat any kind of Food. Real world Lions are more specific in their food eating ability than the general definition of an unknown animal. And it is this functional difference which makes modeling real world Lions as subclasses of this specific definition of Animal a bad fit.
You could easily fix this by having the Animal "eat food" method throw an IncompatibleFoodException, which changes the definition of an Animal from something that "eats food" to something that "eats or rejects food".

This violates the Liskov substitution principle, so it should likely be avoided (as Edwin says, it's really not an Animal if it can't eat Food).
Perhaps against first thought, this will actually not result in an error, but rather will call Animal::feed instead of Lion::feed as expected.
Just reread the title, and to answer the question specifically: No, covariance is not safe here (in terms of behaviour. In terms of syntax it is.).
Quick copy and paste of the question into an example:
class Food{}
class Meat extends Food{}
class Animal{
void feed(Food f){
System.out.println("om nom nom");
}
}
class Lion extends Animal{
void feed(Meat m)
{
System.out.println("OM NOM NOM");
}
}
public class test
{
public static void main(String[] args)
{
foo(new Lion());
}
static void foo(Animal a){
Food f = new Food();
a.feed(f);
}
}
Outputs "om nom nom"

Related

Java Generic method takes a parameter of the class's type

I have the following code:
public class Animal {
public <T extends Animal> void doSomething(T instance) {
//do stuff
}
}
but the parameter to the method should be of the same type as the class it's being called on. E.g. this is valid:
public class Dog extends Animal {}
public class Cat extends Animal {}
Dog dog1 = new Dog();
Dog anotherDog = new Dog();
dog1.doSomething(anotherDog);
But this is NOT valid:
dog1.doSomething(new Cat());
Is there any way to achieve this without implementing the method on all the subclasses? Do don't want to do that because there are a lot of subclasses and it would be too repetitive.
Generics serve to link things together. They tell the compiler that relationships exist between 2 different places that types occur. However, in your signature, T occurs only once: As parameter. This is useless. Why not just write void doSomething(Animal instance)? Your code is just a more complicated, and less flexible way of writing that. After all, any animal, even an instance of a subclass of animal, is an animal. There is nothing you can pass to the method <T extends Animal> void doSomething(T animal) that you cannot pass to void doSomething(Animal animal)!
What you want is both not possible and non-sensical. Imagine it was possible to tell java that the parameter of doSomething must be of the same type as the receiver of doSomething, then, consider this code:
Dog dog = new Dog();
Cat cat = new Cat();
Animal dogA = dog; // dogA and dog are pointing at the exact same object!
Animal catA = cat; // dogA and dog are pointing at the exact same object!
dogA.doSomething(catA); // so this would compile and run, then.
Look at that last line. No amount of type-based insistence that 'the parameter must be of the same type as the receiver' you care to add to java can ever make the compiler refuse to compile this code. And yet there is no difference between that and dog.doSomething(cat), because dog and dogA as well as cat and catA are referring to the same object.
And yet, that is evidently what you want. Thus, what you want is not a sensible thing to want.
There are things you can do, but this almost always leads to more problems. You have to generify your own type:
public class Animal<S extends Animal<S>> {
public void doToSibling(S other) {}
}
But this requires you to declare: class Dog extends Animal<Dog>, and there is nothing actually stopping you from class Dog extends Animal<Cat>. The S is not so much 'self type' as 'the thing I can do doToSibling to'.
I don't think there is an implicit way to reference to an overriding class.
You can declare the reqired subtype as generic argument on animal itself to have the described effect.
public class Animal<T extends Animal<?>> {
public void doSomething(final T instance) {
//do stuff
}
}
public class Dog extends Animal<Dog> {}
public class Cat extends Animal<Cat> {}
That beeing said, in practice it is hard to imagine where you want to go from here. What could a method contain that only two dogs can do but two different animals can't but also can be implemented with the same code?
This is often the point where you want to overthink if a common abstract base-class really is helpful in the long run. If the implementation code turns out to be different for all the animals, maybe a common interface on independent classes might be the better option.

how to achieve polymorphism in java [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question appears to be off-topic because it lacks sufficient information to diagnose the problem. Describe your problem in more detail or include a minimal example in the question itself.
Closed 8 years ago.
Improve this question
i can't understand the following program, how to achieve polymorphism in this coding, please explain in simple way...because i am not strong knowledge in java...
class Animal
{
eat() //here this class has one method
}
class Dog extends Animals
{}
class Cat extends Animals
{}
class Wolf extends Animals
{}
class MyMain
{
public static void main(String args[])
{
Animals[] A=new Animals[3];
A[0]=new Dog(); //parent object reference is used to refer child object
A[1]=new Cat();
A[2]=new Wolf();
for(int i=0;i<3;i++)
A[i].eat();
}
please anybody explain this
which book i have to study for improve knowledge in java?
Polymorphism in simple terms
Polymorphism means "Many forms or shapes", which is a phenomenon where objects behave differently although they are closely related. In the following example we have Cat, Dog and Wolf which are all Animal therefore are related but they perform "makesound" differently. In Java the fact that they are related is denoted by Inheritance, the behavior is denoted by a Method and this phenomenon is called Polymorphism.
Polymorphism using your example
I would declare makesound() instead of eat() since it explains it clearly:
class Animal
{
// This method will be overridden by Dog, Wolf and Cat classes.
makesound(){
System.out.println("make sound"); }
}
class Dog extends Animals
{
makesound()
{System.out.println("Bau");}
}
class Cat extends Animals
{
makesound(){System.out.println("Miao");}
}
class Wolf extends Animals
{
makesound(){System.out.println("Uuuu");}
}
class MyMain
{
public static void main(String args[])
{
/* This is where polymorphism happens, although A[0],A[1],A[2] are all Animals,
at run-time we realize that A[0] is infact dog, A[1] is cat and A[2] is wolf
so when call makesound on these objects, the method behaves differently so the
name polymorphism.*/
Animals[] A=new Animals[3];
A[0]=new Dog();
A[1]=new Cat();
A[2]=new Wolf();
for(int i=0;i<3;i++)
A[i].makesound();
}
On a sidenote before you try to understand what polymorphism, please read what method overriding is: http://docs.oracle.com/javase/tutorial/java/IandI/override.html
Polymorphism is the property of different members of a given hierarchy to have different implementation of a given method. In this case to demonstrate polymorphism you need to provide different implementations of eat(or some other method that you add to the base class Animal) for the different child classes.
From Java Tutorial:
The dictionary definition of polymorphism refers to a principle in biology in which an organism or species can have many different forms or stages. This principle can also be applied to object-oriented programming and languages like the Java language. Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class.
All the subclasses of Animals will share the method eat(), then when you declare your array:
Animals[] A = new Animals[3];
and you initialize its elements:
A[0] = new Dog();
A[1] = new Cat();
A[2] = new Wolf();
you will be able to call the method eat() on each of these objects because of polymorphism.
A example for polymorphism in this case would be:
class Dog extends Animals {
#Override
void eat() {
System.out.printf("Dog eats a bone");
}
}
class Cat extends Animals {
#Override
void eat() {
System.out.printf("Cat eats a mouse");
}
}
class Wolf extends Animals {
#Override
void eat() {
System.out.printf("Wolf eat a living animal");
}
}
Now you just have to call .eat() on your Array of Animals and see the magic happen.
See OracleDocs - Polymorphism for further information about this.
All of these class definitions:
class Dog extends Animals
{}
class Cat extends Animals
{}
class Wolf extends Animals
{}
define new classes that are subclasses of the Animals class.
The dictionary definition of polymorphism refers to a principle in biology in which an organism or species can have many different forms or stages. This principle can also be applied to object-oriented programming and languages like the Java language. Subclasses of a class can define their own unique behaviors and yet share some of the same functionality of the parent class.
As illustrated in the picture above, subclasses inherit some features of the base class and inside them you have access to both the subclass and subclass features(that are visible to subclass).
Some advantages of polymorphism:
Same interface could be used for creating methods with different implementations
Reduces the volume of work in terms of distinguishing and handling various objects
Supports building extensible systems
Complete implementation can be replaced by using same method signatures
Polymorphism can be explained better if you use an interface (because it can not be instantiated):
interface Animal {
void makeSomeNoise();
}
class Cow implements Animal {
public void makeSomeNoise() {
System.out.println("Moo!");
}
}
class Fox implements Animal {
public void makeSomeNoise() {
System.out.println("Ring-ding-ding-ding-dingeringeding!");
}
}
This shows that an animal can not make any noise, but a cow and a fox can. But they make different noises. This is the "principle in biology in which an organism or species can have many different forms or stages". Basically one thing can many different faces.
If you now declare your array like:
Animal[] animals = new Animal[2];
animals[0] = new Cow();
animals[1] = new Fox();
And then let them make some noise with:
animals[0].makeSomeNoise();
animals[1].makeSomeNoise();
You would get following output:
Moo!
Ring-ding-ding-ding-dingeringeding!
So you have two animals but they make different noises.

Should I use different method names or overload parameters in Java?

I have come up with two different ways to implement a few methods in my class:
class Zoo {
public void addTiger(Tiger tiger);
public void addEmu(Emu emu);
// ...
}
class Zoo {
public void add(Tiger tiger);
public void add(Emu emu);
}
The only difference between the two, that I can see, is verbosity - but am I missing something more fundamental? Will one approach make something more difficult in the future?
What's the difference between adding a Tiger and adding an Emu? Why not make an Animal interface?
I would do something like:
class Tiger implements Animal { }
class Emu implements Animal { }
class Zoo {
void add(Animal animal) { }
}
Zoo zoo = new Zoo();
zoo.add(new Tiger());
zoo.add(new Emu());
But there won't be a big difference in your two approaches, they are both equally right or wrong, since the violate the SOLID principles.
If, in the future, you will decide to merge Emu and Tiger by making them both implement the same interface or extend the same class, and therefore merge the two methods, using
class Zoo {
public void add(Tiger tiger);
public void add(Emu emu);
}
will ease your job because you won't need to change anything in the places that use your method.
So yes, the first approach could make something more difficult in the future.
Base on context that you'are using.
In this context, that Tiger and Emu both is Animal. I prefer using overloading method, it will make sense. And, if Tiger and Emu both inherit from Animal class. You can declare an array of animal:
Animal[] zoo;
and this zoo both contains Tiger and Emu. You can do this :
for (int i = 0; i < zoo.length; i++) {
BigZoo.add(zoo[i]);
}
In OOP, we say this is polymorphism.
But, if those things are two different meaning. For example, A server has two things to add: User and Data. It makes sense :
addUser(User user);
addData(Data data);
rather than:
add(User user);
add(Data data);
Hope this help you :)

Why different types of object reference is allowed in Java?

I wonder why it is allowed to have different type of object reference?
For example;
Animal cow = new Cow();
Can you please give an example where it is useful to use different type of object reference?
Edit:Cow extends Animal
This is at the heart of polymorphism and abstraction. For example, it means that I can write:
public void handleData(InputStream input) {
...
}
... and handle any kind of input stream, whether that's from a file, network, in-memory etc. Or likewise, if you've got a List<String>, you can ask for element 0 of it regardless of the implementation, etc.
The ability to treat an instance of a subclass as an instance of a superclass is called Liskov's Substitution Principle. It allows for loose coupling and code reuse.
Also read the Polymorphism part of the Java tutorial for more information.
On a simpler note, this enables polymorphism. For example you can have several objects that derive from Animal and all are handle similar.
You could have something like:
Animal[] myAnimal = {new Cow(), new Dog(), new Cat()};
foreach (Animal animal in myAnimal)
animal.Feed();
The Feed() method must then be overriden within each child class.
By the way, code is C#-like but concept is the same in Java.
This is basically a concept of standardization.
We know that each animal have some common features. Let us take an example of eating and sleeping, but each animal can have different way of eating or sleeping ... then we can define
public abstract class Animal
{
public abstract void Eat();
public abstract void Sleep();
}
//Now Define them in various classes..
public class Cow extends Animal
{
pubic void Eat()
{
//process of eating grass
}
public void Sleep()
{
//process of sleeping
}
}
public class Lion extends Animal
{
public void Eat()
{
//process of eating flesh
}
public void Sleep()
{
//process of sleep
}
}
Now you do not have to define different objects to different classes... just use Animal and call generally
public class MyClass
{
public static void main(String[] args)
{
Animal _animal = new //think the type of animal is coming dynamically
//you can simply call
_animal.Eat();
_animal.Sleep();
// irrespective of checking that what can be the animal type, it also reduces many if else
}
}
This is called polymorphism and it's one of the most powerful aspects of Java.
Polymorphism allows you to treat different objects the same.
It's a great way to create re-usable, flexible code.
Unfortunately it's a part of Java that new programmers often take awhile to understand.
The example you've provided involves inheritance (extending a class).
Another way to enjoy the benefits of polymorphism is to use interfaces.
Different classes that implement the same interface can be treated the same:
class Dog extends Animal implements Talker {
public void speak() {
System.out.println("Woof woof");
}
}
class Programmer implements Talker {
public void speak() {
System.out.println("Polymorphism rocks!");
}
}
interface Talker {
public void speak();
}
public static void testIt() {
List<Talker> talkerList = new ArrayList<Talker>();
talkerList.add(new Dog());
talkerList.add(new Programmer());
for (Talker t : talkerList) {
t.speak();
}
}
Simply putting all Cows are Animals. So JAVA understands that when Cow extends Animal, a Cow can also be called as Animal.
This is Polymorphism as others have pointed out. You can extend Animal with Dog and say that Dog is also an Animal.
In another class/method you might want to use different implementations of the same interface. Following your example, you might have something like:
public void feed( Animal animal ) {
animal.getHome().insertFood(animal.getFavFood());
}
Now you can implement the details in your animal classes and don't have to extend this method anytime you add a new animal to your programm.
So in some cases you need the common interface in order not to implement a method for each implementation, whereas on other occasions, you will need to use the explicit implementation.
This is an inheritance 101 question.
It allows objects that share common functionality to be treated alike.
It also allows specific implementations to be supplied at runtime that are subclasses of an abstract type.
I could probably ramble on for ages. Perhaps thus question is just too broad to answer here.

Is there more to an interface than having the correct methods

So lets say I have this interface:
public interface IBox
{
public void setSize(int size);
public int getSize();
public int getArea();
//...and so on
}
And I have a class that implements it:
public class Rectangle implements IBox
{
private int size;
//Methods here
}
If I wanted to use the interface IBox, i can't actually create an instance of it, in the way:
public static void main(String args[])
{
Ibox myBox=new Ibox();
}
right? So I'd actually have to do this:
public static void main(String args[])
{
Rectangle myBox=new Rectangle();
}
If that's true, then the only purpose of interfaces is to make sure that the class which implements an interface has got the correct methods in it as described by an interface? Or is there any other use of interfaces?
Interfaces are a way to make your code more flexible. What you do is this:
Ibox myBox=new Rectangle();
Then, later, if you decide you want to use a different kind of box (maybe there's another library, with a better kind of box), you switch your code to:
Ibox myBox=new OtherKindOfBox();
Once you get used to it, you'll find it's a great (actually essential) way to work.
Another reason is, for example, if you want to create a list of boxes and perform some operation on each one, but you want the list to contain different kinds of boxes. On each box you could do:
myBox.close()
(assuming IBox has a close() method) even though the actual class of myBox changes depending on which box you're at in the iteration.
What makes interfaces useful is not the fact that "you can change your mind and use a different implementation later and only have to change the one place where the object is created". That's a non-issue.
The real point is already in the name: they define an interface that anyone at all can implement to use all code that operates on that interface. The best example is java.util.Collections which provides all kinds of useful methods that operate exclusively on interfaces, such as sort() or reverse() for List. The point here is that this code can now be used to sort or reverse any class that implements the List interfaces - not just ArrayList and LinkedList, but also classes that you write yourself, which may be implemented in a way the people who wrote java.util.Collections never imagined.
In the same way, you can write code that operates on well-known interfaces, or interfaces you define, and other people can use your code without having to ask you to support their classes.
Another common use of interfaces is for Callbacks. For example, java.swing.table.TableCellRenderer, which allows you to influence how a Swing table displays the data in a certain column. You implement that interface, pass an instance to the JTable, and at some point during the rendering of the table, your code will get called to do its stuff.
One of the many uses I have read is where its difficult without multiple-inheritance-using-interfaces in Java :
class Animal
{
void walk() { }
....
.... //other methods and finally
void chew() { } //concentrate on this
}
Now, Imagine a case where:
class Reptile extends Animal
{
//reptile specific code here
} //not a problem here
but,
class Bird extends Animal
{
...... //other Bird specific code
} //now Birds cannot chew so this would a problem in the sense Bird classes can also call chew() method which is unwanted
Better design would be:
class Animal
{
void walk() { }
....
.... //other methods
}
Animal does not have the chew() method and instead is put in an interface as :
interface Chewable {
void chew();
}
and have Reptile class implement this and not Birds (since Birds cannot chew) :
class Reptile extends Animal implements Chewable { }
and incase of Birds simply:
class Bird extends Animal { }
The purpose of interfaces is polymorphism, a.k.a. type substitution. For example, given the following method:
public void scale(IBox b, int i) {
b.setSize(b.getSize() * i);
}
When calling the scale method, you can provide any value that is of a type that implements the IBox interface. In other words, if Rectangle and Square both implement IBox, you can provide either a Rectangle or a Square wherever an IBox is expected.
Interfaces allow statically typed languages to support polymorphism. An Object Oriented purist would insist that a language should provide inheritance, encapsulation, modularity and polymorphism in order to be a fully-featured Object Oriented language. In dynamically-typed - or duck typed - languages (like Smalltalk,) polymorphism is trivial; however, in statically typed languages (like Java or C#,) polymorphism is far from trivial (in fact, on the surface it seems to be at odds with the notion of strong typing.)
Let me demonstrate:
In a dynamically-typed (or duck typed) language (like Smalltalk), all variables are references to objects (nothing less and nothing more.) So, in Smalltalk, I can do this:
|anAnimal|
anAnimal := Pig new.
anAnimal makeNoise.
anAnimal := Cow new.
anAnimal makeNoise.
That code:
Declares a local variable called anAnimal (note that we DO NOT specify the TYPE of the variable - all variables are references to an object, no more and no less.)
Creates a new instance of the class named "Pig"
Assigns that new instance of Pig to the variable anAnimal.
Sends the message makeNoise to the pig.
Repeats the whole thing using a cow, but assigning it to the same exact variable as the Pig.
The same Java code would look something like this (making the assumption that Duck and Cow are subclasses of Animal:
Animal anAnimal = new Pig();
duck.makeNoise();
anAnimal = new Cow();
cow.makeNoise();
That's all well and good, until we introduce class Vegetable. Vegetables have some of the same behavior as Animal, but not all. For example, both Animal and Vegetable might be able to grow, but clearly vegetables don't make noise and animals cannot be harvested.
In Smalltalk, we can write this:
|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.
aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.
This works perfectly well in Smalltalk because it is duck-typed (if it walks like a duck, and quacks like a duck - it is a duck.) In this case, when a message is sent to an object, a lookup is performed on the receiver's method list, and if a matching method is found, it is called. If not, some kind of NoSuchMethodError exception is thrown - but it's all done at runtime.
But in Java, a statically typed language, what type can we assign to our variable? Corn needs to inherit from Vegetable, to support grow, but cannot inherit from Animal, because it does not make noise. Cow needs to inherit from Animal to support makeNoise, but cannot inherit from Vegetable because it should not implement harvest. It looks like we need multiple inheritance - the ability to inherit from more than one class. But that turns out to be a pretty difficult language feature because of all the edge cases that pop up (what happens when more than one parallel superclass implement the same method?, etc.)
Along come interfaces...
If we make Animal and Vegetable classes, with each implementing Growable, we can declare that our Cow is Animal and our Corn is Vegetable. We can also declare that both Animal and Vegetable are Growable. That lets us write this to grow everything:
List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());
for(Growable g : list) {
g.grow();
}
And it lets us do this, to make animal noises:
List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
a.makeNoise();
}
The advantage to the duck-typed language is that you get really nice polymorphism: all a class has to do to provide behavior is provide the method. As long as everyone plays nice, and only sends messages that match defined methods, all is good. The downside is that the kind of error below isn't caught until runtime:
|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.
Statically-typed languages provide much better "programming by contract," because they will catch the two kinds of error below at compile-time:
// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();
farmObject makeNoise();
--
// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest();
So....to summarize:
Interface implementation allows you to specify what kinds of things objects can do (interaction) and Class inheritance lets you specify how things should be done (implementation).
Interfaces give us many of the benefits of "true" polymorphism, without sacrificing compiler type checking.
Normally Interfaces define the interface you should use (as the name says it ;-) ). Sample
public void foo(List l) {
... do something
}
Now your function foo accepts ArrayLists, LinkedLists, ... not only one type.
The most important thing in Java is that you can implement multiple interfaces but you can only extend ONE class! Sample:
class Test extends Foo implements Comparable, Serializable, Formattable {
...
}
is possible but
class Test extends Foo, Bar, Buz {
...
}
is not!
Your code above could also be: IBox myBox = new Rectangle();. The important thing is now, that myBox ONLY contains the methods/fields from IBox and not the (possibly existing) other methods from Rectangle.
I think you understand everything Interfaces do, but you're not yet imagining the situations in which an Interface is useful.
If you're instantiating, using and releasing an object all within a narrow scope (for example, within one method call), an Interface doesn't really add anything. Like you noted, the concrete class is known.
Where Interfaces are useful is when an object needs to be created one place and returned to a caller that may not care about the implementation details. Let's change your IBox example to an Shape. Now we can have implementations of Shape such as Rectangle, Circle, Triangle, etc., The implementations of the getArea() and getSize() methods will be completely different for each concrete class.
Now you can use a factory with a variety of createShape(params) methods which will return an appropriate Shape depending on the params passed in. Obviously, the factory will know about what type of Shape is being created, but the caller won't have to care about whether it's a circle, or a square, or so on.
Now, imagine you have a variety of operations you have to perform on your shapes. Maybe you need to sort them by area, set them all to a new size, and then display them in a UI. The Shapes are all created by the factory and then can be passed to the Sorter, Sizer and Display classes very easily. If you need to add a hexagon class some time in the future, you don't have to change anything but the factory. Without the Interface, adding another shape becomes a very messy process.
you could do
Ibox myBox = new Rectangle();
that way you are using this object as Ibox and you don't care that its really Rectangle .
WHY INTERFACE??????
It starts with a dog. In particular, a pug.
The pug has various behaviors:
public class Pug {
private String name;
public Pug(String n) { name = n; }
public String getName() { return name; }
public String bark() { return "Arf!"; }
public boolean hasCurlyTail() { return true; } }
And you have a Labrador, who also has a set of behaviors.
public class Lab {
private String name;
public Lab(String n) { name = n; }
public String getName() { return name; }
public String bark() { return "Woof!"; }
public boolean hasCurlyTail() { return false; } }
We can make some pugs and labs:
Pug pug = new Pug("Spot");
Lab lab = new Lab("Fido");
And we can invoke their behaviors:
pug.bark() -> "Arf!"
lab.bark() -> "Woof!"
pug.hasCurlyTail() -> true
lab.hasCurlyTail() -> false
pug.getName() -> "Spot"
Let's say I run a dog kennel and I need to keep track of all the dogs I'm housing. I need to store my pugs and labradors in separate arrays:
public class Kennel {
Pug[] pugs = new Pug[10];
Lab[] labs = new Lab[10];
public void addPug(Pug p) { ... }
public void addLab(Lab l) { ... }
public void printDogs() { // Display names of all the dogs } }
But this is clearly not optimal. If I want to house some poodles, too, I have to change my Kennel definition to add an array of Poodles. In fact, I need a separate array for each kind of dog.
Insight: both pugs and labradors (and poodles) are types of dogs and they have the same set of behaviors. That is, we can say (for the purposes of this example) that all dogs can bark, have a name, and may or may not have a curly tail. We can use an interface to define what all dogs can do, but leave it up to the specific types of dogs to implement those particular behaviors. The interface says "here are the things that all dogs can do" but doesn't say how each behavior is done.
public interface Dog
{
public String bark();
public String getName();
public boolean hasCurlyTail(); }
Then I slightly alter the Pug and Lab classes to implement the Dog behaviors. We can say that a Pug is a Dog and a Lab is a dog.
public class Pug implements Dog {
// the rest is the same as before }
public class Lab implements Dog {
// the rest is the same as before
}
I can still instantiate Pugs and Labs as I previously did, but now I also get a new way to do it:
Dog d1 = new Pug("Spot");
Dog d2 = new Lab("Fido");
This says that d1 is not only a Dog, it's specifically a Pug. And d2 is also a Dog, specifically a Lab.
We can invoke the behaviors and they work as before:
d1.bark() -> "Arf!"
d2.bark() -> "Woof!"
d1.hasCurlyTail() -> true
d2.hasCurlyTail() -> false
d1.getName() -> "Spot"
Here's where all the extra work pays off. The Kennel class become much simpler. I need only one array and one addDog method. Both will work with any object that is a dog; that is, objects that implement the Dog interface.
public class Kennel {
Dog[] dogs = new Dog[20];
public void addDog(Dog d) { ... }
public void printDogs() {
// Display names of all the dogs } }
Here's how to use it:
Kennel k = new Kennel();
Dog d1 = new Pug("Spot");
Dog d2 = new Lab("Fido");
k.addDog(d1);
k.addDog(d2);
k.printDogs();
The last statement would display:
Spot Fido
An interface give you the ability to specify a set of behaviors that all classes that implement the interface will share in common. Consequently, we can define variables and collections (such as arrays) that don't have to know in advance what kind of specific object they will hold, only that they'll hold objects that implement the interface.
A great example of how interfaces are used is in the Collections framework. If you write a function that takes a List, then it doesn't matter if the user passes in a Vector or an ArrayList or a HashList or whatever. And you can pass that List to any function requiring a Collection or Iterable interface too.
This makes functions like Collections.sort(List list) possible, regardless of how the List is implemented.
This is the reason why Factory Patterns and other creational patterns are so popular in Java. You are correct that without them Java doesn't provide an out of the box mechanism for easy abstraction of instantiation. Still, you get abstraction everywhere where you don't create an object in your method, which should be most of your code.
As an aside, I generally encourage people to not follow the "IRealname" mechanism for naming interfaces. That's a Windows/COM thing that puts one foot in the grave of Hungarian notation and really isn't necessary (Java is already strongly typed, and the whole point of having interfaces is to have them as largely indistinguishable from class types as possible).
Don't forget that at a later date you can take an existing class, and make it implement IBox, and it will then become available to all your box-aware code.
This becomes a bit clearer if interfaces are named -able. e.g.
public interface Saveable {
....
public interface Printable {
....
etc. (Naming schemes don't always work e.g. I'm not sure Boxable is appropriate here)
the only purpose of interfaces is to make sure that the class which implements an interface has got the correct methods in it as described by an interface? Or is there any other use of interfaces?
I am updating the answer with new features of interface, which have introduced with java 8 version.
From oracle documentation page on summary of interface :
An interface declaration can contain
method signatures
default methods
static methods
constant definitions.
The only methods that have implementations are default and static methods.
Uses of interface:
To define a contract
To link unrelated classes with has a capabilities (e.g. classes implementing Serializable interface may or may not have any relation between them except implementing that interface
To provide interchangeable implementation e.g. strategy pattern
Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces
Organize helper methods in your libraries with static methods ( you can keep static methods specific to an interface in the same interface rather than in a separate class)
Some related SE questions with respect to difference between abstract class and interface and use cases with working examples:
What is the difference between an interface and abstract class?
How should I have explained the difference between an Interface and an Abstract class?
Have a look at documentation page to understand new features added in java 8 : default methods and static methods.
The purpose of interfaces is abstraction, or decoupling from implementation.
If you introduce an abstraction in your program, you don't care about the possible implementations. You are interested in what it can do and not how, and you use an interface to express this in Java.
If you have CardboardBox and HtmlBox (both of which implement IBox), you can pass both of them to any method that accepts a IBox. Even though they are both very different and not completely interchangable, methods that don't care about "open" or "resize" can still use your classes (perhaps because they care about how many pixels are needed to display something on a screen).
Interfaces where a fetature added to java to allow multiple inheritance. The developers of Java though/realized that having multiple inheritance was a "dangerous" feature, that is why the came up with the idea of an interface.
multiple inheritance is dangerous because you might have a class like the following:
class Box{
public int getSize(){
return 0;
}
public int getArea(){
return 1;
}
}
class Triangle{
public int getSize(){
return 1;
}
public int getArea(){
return 0;
}
}
class FunckyFigure extends Box, Triable{
// we do not implement the methods we will used the inherited ones
}
Which would be the method that should be called when we use
FunckyFigure.GetArea();
All the problems are solved with interfaces, because you do know you can extend the interfaces and that they wont have classing methods... ofcourse the compiler is nice and tells you if you did not implemented a methods, but I like to think that is a side effect of a more interesting idea.
Here is my understanding of interface advantage. Correct me if I am wrong.
Imagine we are developing OS and other team is developing the drivers for some devices.
So we have developed an interface StorageDevice. We have two implementations of it (FDD and HDD) provided by other developers team.
Then we have a OperatingSystem class which can call interface methods such as saveData by just passing an instance of class implemented the StorageDevice interface.
The advantage here is that we don't care about the implementation of the interface. The other team will do the job by implementing the StorageDevice interface.
package mypack;
interface StorageDevice {
void saveData (String data);
}
class FDD implements StorageDevice {
public void saveData (String data) {
System.out.println("Save to floppy drive! Data: "+data);
}
}
class HDD implements StorageDevice {
public void saveData (String data) {
System.out.println("Save to hard disk drive! Data: "+data);
}
}
class OperatingSystem {
public String name;
StorageDevice[] devices;
public OperatingSystem(String name, StorageDevice[] devices) {
this.name = name;
this.devices = devices.clone();
System.out.println("Running OS " + this.name);
System.out.println("List with storage devices available:");
for (StorageDevice s: devices) {
System.out.println(s);
}
}
public void saveSomeDataToStorageDevice (StorageDevice storage, String data) {
storage.saveData(data);
}
}
public class Main {
public static void main(String[] args) {
StorageDevice fdd0 = new FDD();
StorageDevice hdd0 = new HDD();
StorageDevice[] devs = {fdd0, hdd0};
OperatingSystem os = new OperatingSystem("Linux", devs);
os.saveSomeDataToStorageDevice(fdd0, "blah, blah, blah...");
}
}

Categories