Java Forum / General / July 2005
Multiple Inheritance with Interfaces
Will - 15 Jul 2005 14:39 GMT You cannot inherit from more than one super class in Java, but according to all the texts 'Interfaces allow you to 'inherit' from more than one class'. But all an interface gives you is a method name so how on earth does an Interface allow you to use methods from other classes - a method name is just a name. Pls don't refer to 'contracts' as I have read too much about them over and over. Any kind clever person can explain in words on one syllable?
danmcleran@yahoo.com - 15 Jul 2005 14:53 GMT The only thing that comes to mind is to have your class use composition to implement the desired behaviour. Something like this (say you want a class that 'inherits' both Foo and Bar functionality, you do this by holding instances A and B which implement Foo and Bar, respectively):
public interface Foo { public void saySomething(); }
public interface Bar { public void saySomethingElse(); }
public class A implements Foo {
/* (non-Javadoc) * @see Foo#saySomething() */ public void saySomething() { System.out.println("A says something"); }
}
public class B implements Bar {
/* (non-Javadoc) * @see Bar#saySomethingElse() */ public void saySomethingElse() { System.out.println("B says something else"); }
}
public class C implements Foo, Bar {
private final A a_ = new A(); private final B b_ = new B();
/* (non-Javadoc) * @see Foo#saySomething() */ public void saySomething() { this.a_.saySomething(); }
/* (non-Javadoc) * @see Bar#saySomethingElse() */ public void saySomethingElse() { this.b_.saySomethingElse(); }
}
Will - 15 Jul 2005 20:30 GMT Hello Damncl, this seems to work without any interface. See my re-write of class C with NO IMPLEMENTS, it works just the same. We just instantiate an object for class A (& B) and call its method. I don't see what the Interface buys you (where is anything remotely like MI?) I know I am missing the point, but I just don't get it (Interfaces & MI that is).
Here is the code (I have compiled and run it, - no errors)
public class C { //
private final A a_ = new A(); // works without an interface at all!?? private final B b_ = new B(); /* (non-Javadoc) * @see Foo#saySomething() */ public static void main(String [] ds) { A aa = new A(); aa.saySomething(); // calls method from class A without the interface
}
public void saySomething() { this.a_.saySomething(); }
/* (non-Javadoc) * @see Bar#saySomethingElse() */ public void saySomethingElse() { this.b_.saySomethingElse(); } }
public class B implements Bar {
/* (non-Javadoc) * @see Bar#saySomethingElse() */ public void saySomethingElse() { System.out.println("B says something else"); }
} public class A implements Foo {
/* (non-Javadoc) * @see Foo#saySomething() */ public void saySomething() { System.out.println("A says something"); } } public interface Foo { public void saySomething(); }
public interface Bar { public void saySomethingElse(); }
The Interfaces Foo and Bar do not appear to allow class C to MI or 'inherit' from class A and class B. I know about contracts, but where does any form of multiple inheritance come in to it? I thought that if you had a pet class and a animalclass that a dog class could 'inherit' from both by using an Interface? I don't get it (but I am a bit dumb)
danmcleran@yahoo.com - 15 Jul 2005 21:22 GMT Of course you could do this without implementing these interfaces, but if you are trying to mimic multiple inheritance and some other software construct is expecting a class that implements Foo and yet another construct is expecting a class that implements Bar, one could implement both in the same class, i.e. class C. Although class C does not 'extend' class A (i.e. Foo) and class B (i.e. Bar), it implements both interfaces (Foo and Bar) and uses composition to behave like it does (i.e. give the appearance of multiple inheritance of classes A & B).
Here is a modified version of main:
public class Main {
public static void doSomethingWithAClassThatIsAFoo(final Foo f) { f.saySomething(); }
public static void doSomethingWithAClassThatIsABar(final Bar b) { b.saySomethingElse(); }
public static void main(String[] args) { C test = new C();
doSomethingWithAClassThatIsABar(test); doSomethingWithAClassThatIsAFoo(test); } }
Will - 16 Jul 2005 12:25 GMT Hello Damec I ran your code and saw that passing an Interface type object indeed ran the correct methods, but these methods were composed from instantation of objects. So I removed all the interfaces and ran the same code with thae same result. Here is the code:
public interface Foo { // not used public void saySomething(); } public interface Bar { // not used public void saySomethingElse(); }
public class A { // removed implements
public void saySomething() { System.out.println("A says something"); } }
public class B { // removed implements public void saySomethingElse() { System.out.println("B says something else"); } }
public class C { // removed implements
private A a_ = new A(); private B b_ = new B(); public void saySomething() { this.a_.saySomething(); } public void saySomethingElse() { this.b_.saySomethingElse(); } }
public class Main {
// now f is a C public static void doSomethingWithAClassThatIsAFoo(C f) { f.saySomething(); } // now b is a C public static void doSomethingWithAClassThatIsABar(C b) { b.saySomethingElse(); }
public static void main(String[] args) { C test = new C();
doSomethingWithAClassThatIsABar(test); doSomethingWithAClassThatIsAFoo(test); } } OUTPUT: B says something else A says something Press any key to continue...
I must be the only one that does not understand this, I can see that a foo Interface object does the trick, but it is still using good old instantiation of classes A & B to get at the method implementations in A & C & I can do this anyway (MI, Interface or not). I just do an instantation & method call. The Interface seems to do nothing to help except we write more code. And how come real interfaces actually do stuff like compare objects and run threads. Is it method call backs and messaging? Maybe its something so simple that I just cant see it. I have tried & tried to grasp it.
blmblm@myrealbox.com - 16 Jul 2005 15:25 GMT >Hello Damec >I ran your code and saw that passing an Interface [quoted text clipped - 46 lines] > b.saySomethingElse(); > } Um ....
Changing the type of the parameter (from Foo for the first function, and Bar for the section, to C in both cases) takes away the point of the example.
The method doSomethingWithAClassThatIsAFoo() will presumably do something sensible as long as the parameter it is passed belongs to a class with a saySomething() method. An object of class C will work, but so would an object of class A, right? but by making the type of the parameter C, you make it impossible to call this method with a parameter of type A, even though that would (presumably) be a sensible thing to do.
To indicate that doSomethingWithAClassThatIsAFoo() should accept objects of any class that has a saySomething() method, the original code defines an interface Foo containing that method. If classes A and C are declared to "implement Foo", this means that:
(1) Both A and C need to have a saySomething() method.
(2) You can pass an object that's a C (e.g., "test" in main below) to doSomethingWithAClassThatIsAFoo(), but you could also pass it an A, as in the following (untested!!) lines:
A testA = new A(); doSomethingWithAClassThatIsAFoo(testA);
You could also define other classes with saySomething() methods, totally unrelated to A and C, and then pass objects of these classes to doSomethingWithAClassThatIsAFoo(). The only requirement is that the class have a saySomething() method, which you indicate by saying that the class "implements Foo".
Well, I don't know if this is getting clearer or murkier ....
> public static void main(String[] args) { > C test = new C(); [quoted text clipped - 23 lines] >Maybe its something so simple that I just >cant see it. I have tried & tried to grasp it. I also think there must be something very simple that would make all of this clear to you, because I don't think the basic ideas should be beyond someone who has mastered *some* programming language (as it sounds like you have). There must be someone reading this group who can say the magic words that will make the light bulb come on for you, but ....
I think a lot of the responses you're getting are bringing in lots of details and complications that while interesting and relevant probably just confuse you further.
It might help also if you described your previous programming experience, particularly which language(s) you've used before. (I thought this might be in one of your earlier posts, but I didn't find it. Apologies if I just missed it.)
| B. L. Massingill | ObDisclaimer: I don't speak for my employers; they return the favor. Thomas G. Marshall - 16 Jul 2005 23:30 GMT blmblm@myrealbox.com coughed up:
...[rip]...
> I also think there must be something very simple that would make all > of this clear to you, because I don't think the basic ideas should > be beyond someone who has mastered *some* programming language > (as it sounds like you have). There must be someone reading this > group who can say the magic words that will make the light bulb > come on for you, but .... I've seen similar disconnects, and it usually comes from a very deep assumption formed somewhere in the learning process. That low level assumption is incorrect, yet remains the stake in the sand from which all new knowledge is measured.
It gets very tricky for people when that assumption proves to be 90% correct. I'm not sure what that assumption is for the OP just yet.
...[rip]...
 Signature Sometimes life just sucks and then you live.
Dan McLeran - 16 Jul 2005 17:21 GMT I hope this isn't duplicated, but I'm not seeing my earlier post. Anyway, by changing the method signature of the example, you've defeated the purpose of the exercise. The original example had methods that expected arguments of Foo and Bar. What this was doing was forcing the passed arguments to implement the Foo or Bar interfaces. Our class, class C, implemented both of these interfaces and so could be passed to each method. Class C provided the look and feel of multiple inheritance of classes A and B by implementing these interfaces and holding its own copies of A and B. In Java, you cannot extend 2 base classes:
class C extends A,B // won't compile.
My suggestion was to provide interfaces and a class per interface that you wish class C to extend. Then instead of extending A and B, you implement each interface and hold instances of A and B, which receive the forwarded method calls.
Maybe a different example will help you. Let's create a small example where a fire house has employees, one of which is a dog. We create an interface, IAnimal, to describe animal behaviour. We also create an interface, IEmployee, to describe employee behaviour. We have an Animal class that can be extended and an Employee class which can be extended. We will create a WorkingDogHolder class to 'extend' both Animal and Employee by implementing both the IAnimal and IEmployee interfaces and holding instances of Dog and Employee. We will create a Secretary class to pay employees and a Groomer class to groom animals. Because a WorkingDogHolder is both and Animal and an Employee, we need to try and fake some multiple inheritance:
public interface IAnimal { public void eat(); public void receiveGrooming(); }
public interface IEmployee { public void receivePayment(); }
public class Animal implements IAnimal {
/* (non-Javadoc) * @see IAnimal#eat() */ public void eat() { System.out.println("Animals love to eat!"); }
public void receiveGrooming() { System.out.println("Animals love a good grooming"); } }
public class Dog extends Animal { public void eat() { System.out.println("Dogs love to eat!"); }
public void receiveGrooming() { System.out.println("Dogs love a good grooming"); } }
public class Employee implements IEmployee {
/* (non-Javadoc) * @see IEmployee#receivePayment() */ public void receivePayment() { System.out.println("I love payday!"); } }
public class WorkingDogHolder implements IAnimal, IEmployee { private final Employee employee_ = new Employee(); private final Dog dog_ = new Dog();
public void receivePayment() { this.employee_.receivePayment(); this.eat(); }
public void eat() { this.dog_.eat(); }
public void receiveGrooming() { this.dog_.receiveGrooming(); } }
public class Groomer { public void groomAnimal(final IAnimal animal) { animal.receiveGrooming(); } }
public class Secretary{ public void providePayment(final IEmployee employee) { employee.receivePayment(); } }
public class Main {
public static void main(String[] args) { Employee humanEmployee = new Employee(); WorkingDogHolder workingDog = new WorkingDogHolder(); Dog normalDog = new Dog(); Secretary secretary = new Secretary(); Groomer groomer = new Groomer();
secretary.providePayment(humanEmployee); secretary.providePayment(workingDog); //secretary.providePayment(normalDog); //won't compile because a normal dog
//doesn't get paid groomer.groomAnimal(normalDog); groomer.groomAnimal(workingDog); //groomer.groomAnimal(humanEmployee); //won't compile because a human
//can't be groomed in this example } }
Thomas G. Marshall - 17 Jul 2005 00:14 GMT Will coughed up:
> Hello Damec > I ran your code and saw that passing an Interface > type object indeed ran the correct methods, but > these methods were composed from instantation of > objects. ...[rip]...
Would you mind if we start at the beginning with what interfaces are, but in a more example-driven way, rather than hoity toity theory? This is going to be very basic, and hopefully not insult you. But I think there is a misunderstanding somwhere in here. Then you can tell me to what extent you understand what I have to say, so we can procede from there.
Let's start with modeling a bunch of creatures.
Let's pretend that I want to model birds. They know how to fly a certain number of feet. They also know how to chirp. We'll leave the details of how flight and chirping is actually accomplished out of the discussion /on purpose/. Note this is a real class, not an interface.
public class Bird extend Creature { public void fly(int feet) { /* fly code here */ } public void chirp() { /* chirping code here */ } }
Now let's pretend that we also have Bugs. They know how to fly, but they don't know much about chirping, but they can sure run. Birds can't really run.
public class Bug extend Creature { public void fly(int feet) { /* fly code here */ } public void run(int feet) { /* run code here */ } }
And we have Mammals. They know how to run, but not fly nor chirp, nor anything else much:
public class Mammals extend Creature { public void run(int feet) { /* run code here */ } }
We would like to keep track of the creatures that can fly, and of the ones that can run. So we build an interface representing these abilities:
public interface Airborne { void fly(int feet); }
public interface CanRun { void run(int feet); }
And then we make sure that the classes that we already have created implement these interfaces. Implementing the interfaces doesn't make them have any abilities they didn't already have, it just allows us to put them into useful categories (the OO purists are groaning here, but bear with me):
public class Bird implements Airborne { public void fly(int feet) { /* fly code here */ } public void chirp() { /* chirping code here */ } }
public class Bug implements Airborne, CanRun { public void fly(int feet) { /* fly code here */ } public void run(int feet) { /* run code here */ } }
public class Mammals implements CanRun { public void run(int feet) { /* run code here */ } }
Why the heck is this useful? Well let's pretend you had the following objects:
Bird bird1 = new Bird(); Bird bird2 = new Bird(); Bird bird3 = new Bird(); Bug bug1 = new Bug(); Bug bug2 = new Bug(); Mammal mammal1 = new Mammal(); Mammal mammal2 = new Mammal(); Mammal mammal3 = new Mammal(); Mammal mammal4 = new Mammal(); Mammal mammal5 = new Mammal();
You could then create an array of just the creatures that can fly:
Airborne[] flyingCreatures = { bird1, bird2, bird3, bug1, bug2 };
You would not be able to add any of the mammals:
// Error: mammal1 is not an Airborne object: Airborne[] flyingCreatures = { bird1, bird2, bird3, bug1, bug2, mammal1 };
You could then also have a collection of the creatures that run. Note, that some of these also fly:
CanRun[] runningCreatures = {bug1, bug2, mammal1, mammal2, mammal3, mammal4, mammal5}
...but of course, you would not be able to add any birds to this list.
All of this hoo-hah is an enforement of type-safety. You now have a way of specifying only things that fly, and only things that run.
For example, we could create a method that makes the given airborne create fly a mile:
public void flyAMile(Airborne flyingCreature) { flyingCreature.fly(5280); }
And we could then call this:
flyAMile(bird2);
And specifically not this:
flyAMile(mammal4);
I'm betting you have this part down cold already. Do you?
 Signature Sometimes life just sucks and then you live.
Will - 17 Jul 2005 14:57 GMT Thomas, I compiled and ran your code. Indeed, an array of objects that all implement the same interface does exclude non implementer classes. I cast one to the Interface it compiled, but it did not run. Here is the code (based on yours):
public interface Airborne { void fly(int feet); }
public class Bird implements Airborne { public void fly(int feet) { } public void chirp() { } }
public class Bug implements Airborne { public void fly(int feet) { } public void run(int feet) { } }
public class Mammals { public void run(int feet) { } }
public class Tester {
public static void main(String [] args) { Bird bird1 = new Bird(); Bug bug1 = new Bug(); Mammals mammals1 = new Mammals();
Airborne [] flyers = {bird1, bug1, (Airborne)mammals1}; flyers[0].fly(2); flyers[1].fly(7); flyers[2].fly(9); } } Compiles OK but won't run (as expected because mammals is not an Airborne) OUTPUT: java.lang.ClassCastException: Mammals at Tester.main(Tester.java:9) Press any key to continue...
I see that that is useful in OO. Below is a practical example of an interface being used to compare objects. (Comparator) At NO POINT is the Interface method called from the code. But it is being called in reality (its called from somewhere 5 times - I have tested it) This required Interface method is called: -public int compareTo(some Params)-. What or who is calling it 5 times? Note, in my sphere of thinking it (the interface method) is actually doing some work. But I understood that Interface methods have no implementation. Yet it compared objects in a complicated way 5 times!
Here is the working code: (I tested it)
class Person implements Comparable { private String firstName; private String lastName; private int age;
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public int compareTo(Object anotherPerson) throws ClassCastException { if (!(anotherPerson instanceof Person)) throw new ClassCastException("A Person object expected."); int anotherPersonAge = ((Person) anotherPerson).getAge(); return this.age - anotherPersonAge; } }
import java.util.Arrays;
public class Testing {
public static void main(String[] args) { Person[] persons = new Person[4]; persons[0] = new Person(); persons[0].setLastName("Goodyear"); persons[0].setAge(56); persons[1] = new Person(); persons[1].setLastName("Clark"); persons[1].setAge(8); persons[2] = new Person(); persons[2].setLastName("Graff"); persons[2].setAge(16); persons[3] = new Person(); persons[3].setLastName("Goodyear"); persons[3].setAge(69);
System.out.println("Natural Order");
for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); int age = person.getAge(); System.out.println(lastName +". Age:" + age); }
Arrays.sort(persons);
System.out.println(); System.out.println("Sorted by age");
for (int i=0; i<4; i++) { Person person = persons[i]; String lastName = person.getLastName(); int age = person.getAge(); System.out.println(lastName +". Age:" + age); } } }
Thomas G. Marshall - 17 Jul 2005 17:26 GMT Will coughed up:
> Thomas, I compiled and ran your code. > Indeed, an array of objects that all > implement the same interface does exclude > non implementer classes. I cast one to the > Interface it compiled, but it did not run. ...[rip]...
> Airborne [] flyers = {bird1, bug1, (Airborne)mammals1}; > flyers[0].fly(2); [quoted text clipped - 4 lines] > Compiles OK but won't run (as expected > because mammals is not an Airborne) Yes. Well, it compiles ok only because the java compiler does not try particularly hard to see if the mammals reference is of a compatible type to Airborne. It takes the cast and assumes that you know what you're doing. I've often thought that in *simple cases* that the compiler should at least issue a warning with words to the effect of:
"you're attempting a cast to something that does not seem compatible. mammals1 seems to be of type bla bla bla are"
If you attempt a cast to something else entirely
Airborne [] flyers = {bird1, bug1, (String)mammals1};
The compiler will punt with an "incompatible type" error message (it'll compare String to Airborne).
> OUTPUT: > java.lang.ClassCastException: Mammals [quoted text clipped - 8 lines] > reality (its called from somewhere 5 times > - I have tested it) It is being called by Arrays.sort(). Here is what the documentation for Arrays.sort() says:
public static void sort(Object[] a) Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement the Comparable interface. [...]
Each element must implement that Comparable interface, so that Arrays.sort() is guaranteed to have a compareTo() method to call. Arrays.sort() uses the compareTo() method of each of the objects in the array to determine what order to place them in.
If this still confuses you, or if you need a rewording of this, let me know asap.
...[rip]...
 Signature Having a dog that is a purebred does not qualify it for breeding. Dogs need to have several generations of clearances for various illnesses before being bred. If you are breeding dogs without taking care as to the genetic quality of the dog (again, being purebred is *not* enough), you are what is known as a "backyard breeder" and are part of the problem. Most of the congenital problems of present day dogs are traceable directly to backyard breeding. Spay or neuter your pet responsibly, and don't just think that you're somehow the exception and can breed a dog without taking the care described.
Patricia Shanahan - 17 Jul 2005 17:58 GMT > Will coughed up: > [quoted text clipped - 24 lines] > seem compatible. mammals1 seems to be of type > bla bla bla are" I don't think this is an appropriate case for a warning, because I believe it should be possible to remove all warnings from a runtime correct program by appropriate casting etc.
Consider:
class Bat extends Mammals implements Airborne{ ... }
Patricia
Thomas G. Marshall - 17 Jul 2005 22:39 GMT Patricia Shanahan coughed up:
>> Will coughed up: >> [quoted text clipped - 35 lines] > > Patricia I see, and agree, thanks. Muse with me the following case (slightly to the side):
Object mumble = new ArrayList(); String str = (String)mumble;
It is very hard for a compiler to determine what to do in this case, because a carefully timed thread could plant a String into mumble between line 1 and line 2, allowing line 2 to execute without error. The reason that this is difficult for the compiler is because Object is a superclass to String.
But consider this case:
String mumble = "hello"; List list = (List)mumble;
There is *no situation* where mumble can /ever/ become part of the List hierarchy. And in fact the compiler is just fine with kicking out an error:
String str = "hello"; List list = (List)str;
compiler error: javac 1.5.0-beta2 Cast.java:41: inconvertible types found : java.lang.String required: java.util.List List list = (List)mumble; ^ 1 error
...as it should because String is final, and therefore, as in your example, it can never be extended into something that implements List or a List subinterface.
And as you point out
interface Airborne { void fly(int feet); }
class Mammal { public void run(int feet) { } }
class Bat extends Mammal implements Airborne { }
Mammal mammal = new Mammal(); Airborne flyers1 = (Airborne)mammal;
mammal might be assigned a Bat elsewhere, "in time".
Thanks Patricia, for making this clear.
 Signature Having a dog that is a purebred does not qualify it for breeding. Dogs need to have several generations of clearances for various illnesses before being bred. If you are breeding dogs without taking care as to the genetic quality of the dog (again, being purebred is *not* enough), you are what is known as a "backyard breeder" and are part of the problem. Most of the congenital problems of present day dogs are traceable directly to backyard breeding. Spay or neuter your pet responsibly, and don't just think that you're somehow the exception and can breed a dog without taking the care described.
Patricia Shanahan - 17 Jul 2005 23:11 GMT > Patricia Shanahan coughed up: > [quoted text clipped - 48 lines] > line 2, allowing line 2 to execute without error. The reason that this is > difficult for the compiler is because Object is a superclass to String. In theory, at least in some situations, the compiler could apply data flow analysis to bound the classes of objects referenced by variables, beyond the limitations imposed by the variable types. In your example, there is no asynchronous access to local variables, so the compiler could know that the cast must fail at run time.
However, the JLS rules for casting conversion are expressed only in terms of declared, compile-time types. The rules make sense in terms of the question "Could there exist an object would make this cast valid?" but with reference expression treated as being capable of referencing any object whose class is appropriate for its type. Object is a superclass of String, so mumble's type allows it to reference a String.
> But consider this case: > [quoted text clipped - 3 lines] > There is *no situation* where mumble can /ever/ become part of the List > hierarchy. The key fact is that it is possible to deduce that mumble does not reference a List by looking only at the types involved. The finality of String ensures that mumble must reference an actual String, not an object of a hypothetical, List-implementing subclass of String.
The full and gory rules, including distinctions between final and non-final classes, are in the JLS at http://java.sun.com/docs/books/jls/second_edition/html/conversions.doc.html#20232
Patricia
Will - 17 Jul 2005 19:50 GMT Yes Thomas, I looked in the class Array for the method sort(object []) and it was there and needed a Comparable object. It then started calling my implementation of compareTo() and doing a sort() algorithm. So I begin to see that interfaces do something by using classes such as Array, Thread, ActionListener which demand Interface objects and then appear to call our implementations with something useful and similar in functionality to MI. I admit that the dog breeding example left me completely bemused. I simply cannot relate it to programs unless what inherits and what Interfaces is spelt out. I lose the thread of the argument. But the Arrays sort() I understood well. I think I'll get somewhere now. If you get time can you comment on Patricas observation as I did not understand her point, but it could be salient.
Thomas G. Marshall - 17 Jul 2005 22:44 GMT Will coughed up:
> Yes Thomas, I looked in the class Array for the method sort(object []) > and it was there and needed a Comparable object. It then started [quoted text clipped - 14 lines] > If you get time can you comment on Patricas observation as I did not > understand her point, but it could be salient. I commented on it, so hopefully it'll make sense.
The dog breeding (lol) comment is part of a rotating signature. It has nothing whatsoever to do with java nor OO. It has to do with people breeding dogs who don't understand what the heck they are doing.
So don't short out any synapse trying to adapt it to java. Oye! That must've been some mental gymnastics you were going through!!!!!
 Signature Having a dog that is a purebred does not qualify it for breeding. Dogs need to have several generations of clearances for various illnesses before being bred. If you are breeding dogs without taking care as to the genetic quality of the dog (again, being purebred is *not* enough), you are what is known as a "backyard breeder" and are part of the problem. Most of the congenital problems of present day dogs are traceable directly to backyard breeding. Spay or neuter your pet responsibly, and don't just think that you're somehow the exception and can breed a dog without taking the care described.
Will - 18 Jul 2005 15:56 GMT Yes, Thomas, I thought the dog breeder was an Interface that only allowed certain generations of dogs to breed!! (& inherited class illnesses etc). I must have Asbergers.
billreyn@gmail.com - 18 Jul 2005 22:18 GMT Yes Thomas, I thought that we were using interfaces to limit dog types and there was some sort of 'inherited' illness class problem with the dogs. I must have Asbergers. lol
Will - 16 Jul 2005 12:32 GMT Hello Damec I ran your code and saw that passing an Interface type object indeed ran the correct methods, but these methods were composed from instantation of objects. So I removed all the interfaces and ran the same code with thae same result. Here is the code:
public interface Foo { // not used public void saySomething();
}
public interface Bar { // not used public void saySomethingElse();
}
public class A { // removed implements
public void saySomething() { System.out.println("A says something"); }
}
public class B { // removed implements
public void saySomethingElse() { System.out.println("B says something else"); } } public class C
{ // removed implements
private A a_ = new A(); private B b_ = new B(); public void saySomething() { this.a_.saySomething(); } public void saySomethingElse() { this.b_.saySomethingElse(); }
}
public class Main {
// now f is a C public static void doSomethingWithAClassThatIsAFoo(C f) { f.saySomething(); } // now b is a C public static void doSomethingWithAClassThatIsABar(C
b) { b.saySomethingElse(); } public static void main(String[] args) { C test = new C(); doSomethingWithAClassThatIsABar(test); doSomethingWithAClassThatIsAFoo(test
); }
}
OUTPUT: B says something else A says something Press any key to continue...
I must be the only one that does not understand this, I can see that a foo Interface object does the trick, but it is still using good old instantiation of classes A & B to get at the method implementations in A & C & I can do this anyway (MI, Interface or not). I just do an instantation & method call. The Interface seems to do nothing to help except we write more code. And how come real interfaces actually do stuff like compare objects and run threads. Is it method call backs and messaging? Maybe its something so simple that I just cant see it. I have tried & tried to grasp it.
Wibble - 16 Jul 2005 14:32 GMT > Hello Damec > I ran your code and saw that passing an Interface [quoted text clipped - 85 lines] > Maybe its something so simple that I just > cant see it. I have tried & tried to grasp it. You are confused. Real interfaces never do anything, ever at runtime.
They allow a gadget like thread to call passedInRunnable.run() because they defined an interface and require thier callbacks to look a certain way.
Interfaces are always backed by implementations at runtime, including for Runnable, Comparable, Comparator, Serializable, Cloneable etc.
(dont go on about instanceof, constants, reflection or other obfuscations please, it wont help this guy)
Dan McLeran - 16 Jul 2005 16:19 GMT Will,
You have changed the example in a fundamental way by changing the method signatures from something that expects a Foo or Bar to something that expects class C. This completely defeats the original purpose, which was to mimic multiple inheritance. If you want class C to inherit the functionality of both A & B, you cannot do this directly in Java:
class C extends A, B // will not compile
What you can do is implement any number of interfaces you like. So, if you create a class to implement the Foo interface (class A) and create another class to implement the Bar interface (class B) and then create a class that implements both Foo and Bar (class C) then you can provide class C with instances of classes A & B and forward all method calls from interfaces Foo and Bar to those class members. This provides the 'look and feel' of multiple inheritance. Of course, it isn't real multiple inheritance because you could not pass instances of C to a method that expects an instance of A, which you would be able to do if 'real' multiple inheritance was used.
Maybe a different example will help clear things up. Let's use a variation of the Animal hierarchy:
The Animal class is the parent class for all animals.The Employee class is the parent class for all employess of a fire station. The Secretary class hands out the payment for all employees of the fire station. The Secretary only hands out payments to classes that implement the IEmployee interface. The WorkingDogHolder class needs to implement all Animal behaviour and Employee behaviour, because these dogs can be employees. Since most Dogs are not employees, we'll create a Dog class that extends Animal via single inheritance. To provide the look and feel of multiple inheritance for a Dog that is an Employee, we'll create a WorkingDogHolder class that needs to provide behaviour for both Dog and Employee. We'll do this by implementing both IAnimal and IEmployee and holding instances to an Dog class and Employee class. We'll also provide a Groomer class that will groom all animals, but not Employees.
public interface IAnimal { public void eat(); public void receiveGrooming(); }
public interface IEmployee { public void receivePayment(); }
public class Animal implements IAnimal {
/* (non-Javadoc) * @see IAnimal#eat() */ public void eat() { System.out.println("Animals love to eat!"); }
public void receiveGrooming() { System.out.println("Animals love a good grooming"); } }
public class Dog extends Animal { public void eat() { System.out.println("Dogs love to eat!"); }
public void receiveGrooming() { System.out.println("Dogs love a good grooming"); } }
public class Employee implements IEmployee {
/* (non-Javadoc) * @see IEmployee#receivePayment() */ public void receivePayment() { System.out.println("I love payday!"); } }
public class WorkingDogHolder implements IAnimal, IEmployee { private final Employee employee_ = new Employee(); private final Dog dog_ = new Dog();
public void receivePayment() { this.employee_.receivePayment(); this.eat(); }
public void eat() { this.dog_.eat(); }
public void receiveGrooming() { this.dog_.receiveGrooming(); } }
public class Groomer { public void groomAnimal(final IAnimal animal) { animal.receiveGrooming(); } }
public class Secretary{ public void providePayment(final IEmployee employee) { employee.receivePayment(); } }
public class Main {
public static void main(String[] args) { Employee humanEmployee = new Employee(); WorkingDogHolder workingDog = new WorkingDogHolder(); Dog normalDog = new Dog(); Secretary secretary = new Secretary(); Groomer groomer = new Groomer();
secretary.providePayment(humanEmployee); secretary.providePayment(workingDog); //secretary.providePayment(normalDog); //won't compile because //a normal dog doesn't //get paid groomer.groomAnimal(normalDog); groomer.groomAnimal(workingDog); //groomer.groomAnimal(humanEmployee); //won't compile because //a human can't //be groomed in this example } }
Raymond DeCampo - 15 Jul 2005 16:02 GMT > You cannot inherit from more than one super class in Java, but > according to all the texts 'Interfaces allow you to 'inherit' from [quoted text clipped - 3 lines] > as I have read too much about them over and over. > Any kind clever person can explain in words on one syllable? I will try to explain, but it will be impossible without using multi-syllabic words, e.g. interface.
Simply put, the type of "inheritance" that interfaces supply do not allow you to inherit any implementation. Interfaces were not designed to do that. So when you implement an interface, you must supply all of the implementation in the implementing class (or one of its superclasses).
HTH, Ray
 Signature XML is the programmer's duct tape.
Thomas G. Marshall - 15 Jul 2005 16:28 GMT Will coughed up:
> You cannot inherit from more than one super class in Java, but > according to all the texts 'Interfaces allow you to 'inherit' from [quoted text clipped - 3 lines] > 'contracts' as I have read too much about them over and over. > Any kind clever person can explain in words on one syllable? There is no way to /directly/ MI the implementations you are looking for using interfaces.
When I was contracted to teach java I was very careful to avoid the common read/heard words:
"java does not have MI, but it has interfaces instead"
Because MI and interfaces do not 1:1 equate.
There are many ways of using interfaces, and they are too much to discuss right now, but they just don't deliver MI (as such) to you. (as they should not---I believe MI to be a way of establishing hard to discover bugs).
"danmcleran"'s post is the most appropos.
 Signature http://www.allexperts.com is a nifty way to get an answer to just about /anything/.
timjowers@gmail.com - 15 Jul 2005 19:28 GMT Yeah, Java interfaces are a punt WRT MI (multiple implements). But probably it's a bug to extend two interfaces which have an identical method sig. Does the javac error message on doing this?
TimJowers
danmcleran@yahoo.com - 15 Jul 2005 19:51 GMT Why is it a bug? I'm sure that there are many interfaces with the method signature void methodName(). Why would it be illegal to extend 2 interfaces that contain methods with the same signature? The Java compiler does not complain and the code compiles and runs fine under JDK 1.4.2.
Lasse Reichstein Nielsen - 15 Jul 2005 20:19 GMT > Why is it a bug? Not a bug, but probably unintentional.
> I'm sure that there are many interfaces with the method signature > void methodName(). Why would it be illegal to extend 2 interfaces > that contain methods with the same signature? Because the *meaning* of the two methods in the two interfaces are probably different. Like the hypothetical interfaces "Exception" and "Javelin", which both have a method "void throw()".
If both interfaces have javadoc for the method, which one will the implementation inherit?
> The Java compiler does not complain and the code compiles and runs > fine under JDK 1.4.2. True. Personally, I would prefer at least a warning.
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Stefan Ram - 15 Jul 2005 20:28 GMT >Because the *meaning* of the two methods in the two interfaces are >probably different. Like the hypothetical interfaces "Exception" and >"Javelin", which both have a method "void throw()". One would have to use another level of indirection:
Instance instance = new Instance(); ExceptionInterface exceptionInterface = instance.getExceptionInterface(); JavalinInterface javelinInterface = instance.getJavelinInterface(); exceptionInterface.throw(); javelinInterface.throw();
Where the getters then might actually create new objects, delegation the throw calls to the instance.
Eric Sosman - 15 Jul 2005 21:00 GMT > Yeah, Java interfaces are a punt WRT MI (multiple implements). But > probably it's a bug to extend two interfaces which have an identical > method sig. Does the javac error message on doing this? No. (You *could* have tried it for yourself ...)
It's an ugly spot in the language, a place where names can "escape" their packages and collide with each other. Them's the breaks.
 Signature Eric.Sosman@sun.com
Tim Tyler - 27 Jul 2005 10:10 GMT timjowers@gmail.com wrote or quoted:
> Yeah, Java interfaces are a punt WRT MI (multiple implements). But > probably it's a bug to extend two interfaces which have an identical > method sig. Does the javac error message on doing this? No.
 Signature __________ |im |yler http://timtyler.org/ tim@tt1lock.org Remove lock to reply.
Andrew McDonagh - 15 Jul 2005 23:18 GMT > You cannot inherit from more than one super class in Java, but > according to all the texts 'Interfaces allow you to 'inherit' from [quoted text clipped - 3 lines] > as I have read too much about them over and over. > Any kind clever person can explain in words on one syllable? Java does not support multiple *implementation* inheritance - as in the C++ does.
It does support multiple interface inheritance.
Interfaces are not purely about the methods that must be implemented. They are first and foremost a typing specification.
class abstract Foo { public abstract void bark(); }
is almost the same as:
interface Foo { void bark(); }
The difference is that interfaces are more tightly constrained as to what we can put in them and how other classes can implement them.
A derived class of the abstract Foo Class would not be allowed to derive from any other class, because Java does not support Multiple *implementation* inheritance.
However, any class can support multiple *interface* implementation.
Interfaces can not have any implementations, only method signatures and constants. Where as abstract classes CAN have some implemented methods.
Andrew
Tim Tyler - 27 Jul 2005 10:22 GMT Will <billreyn@hotmail.com> wrote or quoted:
> You cannot inherit from more than one super class in Java, but > according to all the texts 'Interfaces allow you to 'inherit' from [quoted text clipped - 3 lines] > earth does an Interface allow you to use methods from other > classes - a method name is just a name. A name - and some parameter types - and some constants.
Note that you can do this:
interface Foo { MyType constant1 = new MyType() { void whatever() {...} void you() {...} void like() {...} void here() {...} } }
interface Bar { MyType constant2 = new MyType() { void more() {...} void stuff() {...} void available() {...} void here() {...} } }
That effectively allows you to include code from all over the place by implementing multiple interfaces.
 Signature __________ |im |yler http://timtyler.org/ tim@tt1lock.org Remove lock to reply.
Thomas G. Marshall - 27 Jul 2005 13:59 GMT Tim Tyler coughed up:
> Will <billreyn@hotmail.com> wrote or quoted: > [quoted text clipped - 32 lines] >> im |yler http://timtyler.org/ tim@tt1lock.org Remove lock to >> reply. No, this talks past what he is confused about. I believe his complaint is that when you "include code from all over the place", you tend to have to duplicate it. This is true, or at least to the extent that you must find a way around it: interfaces do not let you inherit implementations, as stated, and as you obviously know.
 Signature Forgetthesong,I'dratherhavethefrontallobotomy...
Tim Tyler - 27 Jul 2005 14:47 GMT Thomas G. Marshall <tgm2tothe10thpower@replacetextwithnumber.hotmail.com> wrote or quoted:
> Tim Tyler coughed up:
> > Note that you can do this: > > [quoted text clipped - 24 lines] > way around it: interfaces do not let you inherit implementations, as stated, > and as you obviously know. It's not quite as bad as all that: You can include an interface which contains a constant instance of an object - intended to do all the work which is to be inherited - and then implement the interface using a bunch of one-line delegates - that call the corresponding methods of the included object.
That way you do effectively multiply-inherit the guts of the implementation - though the programmer has to fill in some associated bubble-gum code to make sure it gets called.
I think it's known as the interface-delegation pattern, or some such - there's a description in:
http://www.mcs.vuw.ac.nz/comp/Publications/CS-TR-98-1.abs.html
The pattern effectively lets you include logic - but not state.
IMO, the biggest problem with multiple inheritance is how to resolve name clashes:
class DefenseStation extends Missile, Employee { void fire() { // fire missile - or fire employee?!? } }
Java offers programmers no assistance with that problem.
 Signature __________ |im |yler http://timtyler.org/ tim@tt1lock.org Remove lock to reply.
Thomas G. Marshall - 27 Jul 2005 19:38 GMT Tim Tyler coughed up:
> Thomas G. Marshall > <tgm2tothe10thpower@replacetextwithnumber.hotmail.com> wrote or [quoted text clipped - 57 lines] > > Java offers programmers no assistance with that problem. I thought that way early on, FWIW. I've since changed my mind to believing that it is infact not a problem at all. Interfaces establish contracts. The only requirement for a java interface contract is that the method be implemented *somewhere* in the class or upstream (let's keep the nitpicking out of it for now :) ) with the signature and return type.
For example, consider this *differing* notion:
interface MethodContract { void method(); }
class A { public void method() {...} }
class B extends A, implements MethodContract{...}
As it turns out, the contract MC is already satisfied by the superclass. There is no "protection" for this either. Mostly, IMO, because it does not need it---it is not a problem either.
 Signature If I can ever figure out how, I hope that someday I'll succeed in my lifetime goal of creating a signature that ends with the word "blarphoogy".
Tim Tyler - 27 Jul 2005 20:08 GMT Thomas G. Marshall <tgm2tothe10thpower@replacetextwithnumber.hotmail.com> wrote or quoted:
> Tim Tyler coughed up:
> > IMO, the biggest problem with multiple inheritance is how to > > resolve name clashes: [quoted text clipped - 24 lines] > There is no "protection" for this either. Mostly, IMO, because it does not > need it---it is not a problem either. If you implement two different interfaces with the same method signature in them in Java, the methods simply clash.
I wouldn't describe that as being "not a problem at all".
 Signature __________ |im |yler http://timtyler.org/ tim@tt1lock.org Remove lock to reply.
Thomas G. Marshall - 29 Jul 2005 00:14 GMT Tim Tyler coughed up:
> Thomas G. Marshall > <tgm2tothe10thpower@replacetextwithnumber.hotmail.com> wrote or [quoted text clipped - 36 lines] > > I wouldn't describe that as being "not a problem at all". You've made a good point. If you have two disparate interfaces whose signatures collide, then yes Houston, you have a problem.
I was more speaking to /overlapping/ interfaces, where a contract is doubly specified, which I see as a non issue. You're absolutely right.
 Signature Framsticks. 3D Artificial Life evolution. You can see the creatures that evolve and how they interact, hunt, swim, etc. (Unaffiliated with me). http://www.frams.alife.pl/
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|