Multiple Inheritance with Interfaces

W

Will

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;
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;
String lastName = person.getLastName();
int age = person.getAge();
System.out.println(lastName +". Age:" + age);
}
}
}
 
T

Thomas G. Marshall

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);
flyers[1].fly(7);
flyers[2].fly(9);
}
}
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
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)

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]...


--
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.
 
P

Patricia Shanahan

Thomas said:
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);
flyers[1].fly(7);
flyers[2].fly(9);
}
}
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"

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
 
W

Will

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.
 
T

Thomas G. Marshall

Patricia Shanahan coughed up:
Thomas said:
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);
flyers[1].fly(7);
flyers[2].fly(9);
}
}
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"

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


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.



--
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.
 
T

Thomas G. Marshall

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
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.

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!!!!!



--
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.
 
P

Patricia Shanahan

Thomas said:
Patricia Shanahan coughed up:
Thomas said:
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);
flyers[1].fly(7);
flyers[2].fly(9);
}
}
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"

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



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.

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:

String mumble = "hello";
List list = (List)mumble;

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
 
W

Will

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.
 
B

billreyn

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
 
T

Tim Tyler

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.
 
T

Tim Tyler

Will said:
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.

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.
 
T

Thomas G. Marshall

Tim Tyler coughed up:
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.

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.
 
T

Tim Tyler

Thomas G. Marshall said:
Tim Tyler coughed up:

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.

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.
 
T

Thomas G. Marshall

Tim Tyler coughed up:
Thomas G. Marshall


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.


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.
 
T

Tim Tyler

Thomas G. Marshall said:
Tim Tyler coughed up:

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.

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".
 
T

Thomas G. Marshall

Tim Tyler coughed up:
Thomas G. Marshall


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".


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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,432
Messages
2,571,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top