Oh man... Mega-Japan is back. I'm curious whether any of my LJ friends know him firsthand? Or at least have heard of him (her?). Anyway, back to our main attraction.
Besides all the namespace and
super ambiguities, there's a fundamental reason.
Suppose we have a class A with two ints and a char.
+-----+-----+---+
| int | int |chr|
+-----+-----+---+
^
A pointer to an object of this class will point to the start of the data, at the caret (modulo some stuff).
Now we create class B extending A, and add a long.
+-----+-----+---+-----------+
| int | int |chr| lng |
+-----+-----+---+-----------+
^
The data is stored in order of the type hierarchy. The pointer still points at the beginning of the data, which is the stuff from class A. If you want the long from B, since you know exactly what data A has, you skip that many bytes (in this case, 8).
Here's the thing -- if a reference to B is interpreted as a reference to A, you can still access the A data, because it's still int-int-char after the pointer. This means that Java doesn't even have to explicitly implement polymorphism, except in the type-safety checks. Every subclass is guaranteed to have the same data in the same order as the superclass, so you can just look at offsets from the pointer and everything works.
If you have multiple inheritance, now you have to combine the data of two object hierarchies, and there's no way to tell for certain where a given piece of data is. Languages like Python get around this with maps of names to locations, which are recalculated whenever you inherit. This is much less efficient, but lets you do fun stuff like dynamic attribute and class creation, or hacky manipulation of what people see when they access something.
Anyway, yeah.