56

First of all... Sorry for this post. I know that there are many many posts on stackoverflow which are discussing multiple inheritance. But I already know that Java does not support multiple inheritance and I know that using interfaces should be an alternative. But I don't get it and see my dilemma:

I have to make changes on a very very large and complex tool written in Java. In this tool there is a data structure built with many different class objects with a linked member hierarchy. Anyway...

  • I have one class Tagged which has multiple methods and returns an object tag depending on the object's class. It needs members and static variables.
  • And a second class called XMLElement allows to link objects and in the end generate a XML file. I also need member and static variables here.
  • Finally, I have these many many data classes which nearly all should extend XMLElement and some of them Tagged.

Ok ok, this won't work since it's only possible to extend just one class. I read very often that everything with Java is ok and there is no need for having multiple inheritance. I believe, but I don't see how an interface should replace inheritance.

  1. It makes no sense to put the real implementation in all data classes since it is the same every time but this would be necessary with interfaces (I think).
  2. I don't see how I could change one of my inheritance classes to an interface. I have variables in here and they have to be exactly there.

I really don't get it so please can somebody explain me how to handle this?

Raedwald
  • 46,613
  • 43
  • 151
  • 237
fpdragon
  • 1,867
  • 4
  • 25
  • 36
  • 1
    check out this thread http://stackoverflow.com/questions/3556652/how-do-java-interfaces-simulate-multiple-inheritance – Bala R Feb 15 '11 at 11:58
  • You said 'I have these many many data classes which nearly all should extend XMLElement and some of them Tagged' and 'It makes no sense to put the real implementation in all data classes since it is the same every time but this would be necessary with interfaces (I think).' --- then your problem is ill-formed in the first place: a class is a type; if the need for many data classes is necessary, then each data class should have its own specific behavior. In other words, each data class should override the member functions in the base class. The contrapositive holds too. – h9uest Jan 06 '15 at 17:22

10 Answers10

81

Actually, I have no good answer other than Java SHOULD have Multiple Inheritance. The whole point that interfaces should be able to replace the need for Multiple Inheritance is like the big lie that when repeated enough times becomes true.

The argument is that Multiple Inheritance causes all these problems (la-di-dah), yet I keep hearing those arguments from Java developers who have never used C++. I also don't EVER remember C++ programmers saying "Gee, I love C++, but if they would only get rid of Multiple Inheritance, it would become a great language". People used it when it was practical and didn't when it wasn't.

Your problem is a classic case of where Multiple Inheritance would be appropriate. Any suggestion to refactor the code is really telling you how to work around the PROBLEM that Java has no Multiple Inheritance.

Also all the discussion that "oh, delegation is better, la-di-dah" is confusing religion with design. There is no right way. Things are either more useful or less useful and that is all.

In your case Multiple Inheritance would be more useful and a more elegant solution.

As far as refactoring your code into a less useful form to satisfy all the religious people who have never used Multiple Inheritance and believe "Multiple Inheritance is bad", I guess you will have to downgrade your code because I don't see Java "improving" in that way any time soon. There are too many people repeating the religious mantra to the point of stupidity that I can't see it ever being added to the language.

Actually, my solution for you would be "x extends Tagged, XMLElement" and that would be all.

...but as you can see from the solutions provided above, most people think that such a solution would be WAY TOO COMPLEX AND CONFUSING!

I would prefer to venture into the "x extends a,b" territory myself, even if it is a very frightening solution that might overwhelm the abilities of most Java programmers.

What is even more amazing about the solutions suggested above is that everyone here who suggested that you refactor your code into "delegation" because Multiple Inheritance is bad, would, if they were confronted with the very same problem, would solve the problem by simply doing: "x extends a,b" and be done with it, and all their religious arguments about "delegation vs inheritance" would disappear. The whole debate is stupid, and it only being advanced by clueless programmers who only demonstrate how well they can recite out of a book and how little they can think for themselves.

You are 100% correct that Multiple Inheritance would help, and no, you are doing anything wrong in your code if you think Java should have it.

SouthRoad
  • 819
  • 6
  • 2
  • 6
    This should be the top answer :) – fhucho Jun 13 '13 at 11:08
  • 3
    amen! and the is true for bloody c# and .net folks. Bertrand Meyer once said that the only reason .net and java does not have multiple inheritance is difficulty of writing a class loader that would support multiple bases classes. – Kemal Erdogan Sep 29 '13 at 15:53
  • 1
    @KemalErdogan: In C++, can you cast any pointer directly to a top-level object type and then downcast directly to its actual type or any supertype thereof? Such ability, and the fact that upcasts and downcasts are identity-preserving, is fundamental to the design of Java. – supercat Dec 17 '13 at 22:59
  • This answer is biased and may well be wrong in this particular case. 'Your problem is a classic case of where Multiple Inheritance would be appropriate.' --- Firstly you're not really sure what the problem is with the few lines of description. Secondly, the problem doesn't sound like a a classic case at all. Rule 2(http://www.parashift.com/c++-faq/mi-disciplines.html) comes with good reasons. Tagged and XMLElement don't sound like ABC's at all. Effectively, a proper C++ multiple inheritance paradigm has the idea of implementing multiple interfaces in the first place. – h9uest Jan 06 '15 at 17:38
  • To support this answer, propriety code may expect your objects to be instances of a specific class. If two pieces of proprietary code expect the same object to be of two classes, neither an instance of the other, the only choices may be to use an extremely ugly hack of substituting interfaces for classes while hoping all the methods are compatible. – Steven Bluen Jun 08 '16 at 17:16
  • This is no answer to the question. If someone says "I need a solution for X, but I can't use Y" then a rant about "Y would be the perfect solution" is no answer. – Sebastian Mar 11 '23 at 08:51
60

You should probably favor composition (and delegation) over inheritance :

public interface TaggedInterface {
    void foo();
}

public interface XMLElementInterface {
    void bar();
}

public class Tagged implements TaggedInterface {
    // ...
}

public class XMLElement implements XMLElementInterface {
    // ...
}

public class TaggedXmlElement implements TaggedInterface, XMLElementInterface {
    private TaggedInterface tagged;
    private XMLElementInterface xmlElement;

    public TaggedXmlElement(TaggedInterface tagged, XMLElementInterface xmlElement) {
        this.tagged = tagged;
        this.xmlElement = xmlElement;
    }

    public void foo() {
        this.tagged.foo();
    }

    public void bar() {
        this.xmlElement.bar();
    }

    public static void main(String[] args) {
        TaggedXmlElement t = new TaggedXmlElement(new Tagged(), new XMLElement());
        t.foo();
        t.bar();
    }
}
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
5

Similar to what Andreas_D suggested but with the use of inner classes. This way you indeed extend each class and can override it in your own code if desired.

interface IBird {
    public void layEgg();
}

interface IMammal {
    public void giveMilk();
}

class Bird implements IBird {
    public void layEgg() {
        System.out.println("Laying eggs...");
    }
}

class Mammal implements IMammal {
    public void giveMilk() {
        System.out.println("Giving milk...");
    }
}

class Platypus implements IMammal, IBird {

    private class LayingEggAnimal extends Bird {}
    private class GivingMilkAnimal extends Mammal {}

    private LayingEggAnimal layingEggAnimal = new LayingEggAnimal();

    private GivingMilkAnimal givingMilkAnimal = new GivingMilkAnimal();

    @Override
    public void layEgg() {
        layingEggAnimal.layEgg();
    }

    @Override
    public void giveMilk() {
        givingMilkAnimal.giveMilk();
    }
}
Community
  • 1
  • 1
SHOJAEI BAGHINI
  • 123
  • 1
  • 5
4

First it makes no sense to put the real implementation in all data classes since it is the same every time but this would be necessary with interfaces (I think).

How about using aggregation for the tags?

  1. Rename your Tagged class to Tags.

  2. Create a Tagged interface:

    interface Tagged { Tags getTags(); }

  3. Let each class that needs to be "tagged", implement Tagged and let it have a tags field, which is returned from getTags.

Second I don't see how I could change one of my inheritance classes to an interface. I have variables in here and they have to be exactly there.

That's right, interfaces can't have instance variables. The data structures storing the tags however, shouldn't necessarily IMO be part of the classes that are tagged. Factor out the tags in a separate data structure.

aioobe
  • 413,195
  • 112
  • 811
  • 826
2

I'd solve it that way: extract interfaces for the Tagged and XMLElement class (maybe you don't need all methods in the public interface). Then, implement both interfaces and the implementing class has a Tagged (your actual concrete Tagged class) and an XMLElement (your actual concrete XMLElement class):

 public class MyClass implements Tagged, XMLElement {

    private Tagged tagged;
    private XMLElement xmlElement;

    public MyClass(/*...*/) {
      tagged = new TaggedImpl();
      xmlElement = new XMLElementImpl();
    }

    @Override
    public void someTaggedMethod() {
      tagged.someTaggedMethod();
    }
  }

  public class TaggedImpl implements Tagged {
    @Override
    public void someTaggedMethod() {
      // so what has to be done
    }
  }

  public interface Tagged {
     public void someTaggedMethod();
  }

(and the same for XMLElement)

Andreas Dolk
  • 113,398
  • 19
  • 180
  • 268
1

Just wondering if one could not simply use inner (member) classes (LRM 5.3.7)? E.g. like this (based on the first answer above):

// original classes:
public class Tagged {
    // ...
}

public class XMLElement {
    // ...
}

public class TaggedXmlElement {
    public/protected/private (static?) class InnerTagged extends Tagged {
      // ...
    }

    public/protected/private (static?) class InnerXmlElement extends XMLElement  {
        // ...
    }

}

This way you have a class TaggedXmlElement which actually contains all elements from the two original classes and within TaggedXmlElement you have access to non-private members of the member classes. Of course one would not use "super", but call member class methods. Alternatively one could extend one of the classes and make the other a member class. There are some restrictions, but I think they can all be worked around.

Einar H.
  • 575
  • 5
  • 5
1

one possible way;

1- You can create base class(es) for common functionality, make it abstract if you dont need to instantiate it.

2- Create interfaces and implement those interfaces in those base class(es). If specific implementation is needed, make the method abstract. each concrete class can have its own impl.

3- extend the abstract base class for in concrete class(es) and implement specific interfaces at this level as well

fmucar
  • 14,361
  • 2
  • 45
  • 50
1

Well using Interface and single base class you are simply stating:

    A) One object can be of only one type (Which is true in real life if you think , A pigeon is a bird, a toyota is a car , etc .. A pigeon is also an animal but every bird is animal anyway, so its hierarchically above the bird type -And in your OOP design Animal class should be base of Bird class in case you need to represent it -) and

    B) can do many different things (A bird can sing, can fly . A car can run , can stop ,etc..)
which also fits the real life objects.

In a world where objects can be of multiple types (horizontally) Let's say a a dolphin is a mammal and also a sea animal, in this case multiple inheritance would make more sense. It would be easier to represent it using multiple inheritance.

Jeff Schreib
  • 119
  • 1
  • 3
0

Using composition would be the way to go as another developer suggested. The main argument against multiple inheritance is the ambiguity created when you're extending from two classes with the same method declaration (same method name & parameters). Personally, however, I think that's a load of crap. A compilation error could easily be thrown in this situation, which wouldn't be much different from defining multiple methods of the same name in a single class. Something like the following code snippet could easily solve this dilema:

public MyExtendedClass extends ClassA, ClassB {
    public duplicateMethodName() {
        return ClassA.duplicateMethodName();
    }
}

Another argument against multiple inheritance is that Java was trying to keep things simple so that amateur developers don't create a web of interdependent classes that could create a messy, confusing software system. But as you see in your case, it also complicates and confuses things when it's not available. Plus, that argument could be used for a 100 other things in coding, which is why development teams have code reviews, style checking software, and nightly builds.

In your particular situation though, you'll have to settle with composition (see Shojaei Baghini's answer). It adds a bit of boiler plate code, but it emulates the same behavior as multiple inheritance.

Greg H
  • 445
  • 4
  • 12
0

I run in a similar problem on Android. I needed to extend a Button and a TextView (both inheriting from View) with additional functions. Due to not having access to their super class, I needed to find another solution. I´ve written a new class which encapsulates all the implementations:

class YourButton extends Button implements YourFunctionSet {
    private Modifier modifier;

    public YourButton(Context context) {
        super(context);
        modifier = new Modifier(this);
    }

    public YourButton(Context context, AttributeSet attrs) {
        super(context, attrs);
        modifier = new Modifier(this);
    }

    public YourButton(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        modifier = new Modifier(this);
    }

    @Override
    public void generateRandomBackgroundColor() {
        modifier.generateRandomBackgroundColor();
    }
}

class Modifier implements YourFunctionSet {

    private View view;

    public Modifier(View view) {
        this.view = view;
    }

    @Override
    public void generateRandomBackgroundColor() {
        /**
         * Your shared code
         *
         * ......
         *
         * view.setBackgroundColor(randomColor);
         */
    }
}


interface YourFunctionSet {
    void generateRandomBackgroundColor();
}

The problem here is, your classes need the same super class. You can also try to use different classes, but check which type it is from, for example

public class Modifier{
private View view;
private AnotherClass anotherClass;

public Modifier(Object object) {
    if (object instanceof View) {
        this.view = (View) object;
    } else if (object instanceof AnotherClass) {
        this.anotherClass = (AnotherClass) object;
    }
}

public void generateRandomBackgroundColor(){
    if(view!=null){
        //...do
    }else if(anotherClass!=null){
        //...do
    }
}
}

So here is basically my Modifier class the class which encapsulates all implementations.

Hope this helps someone.

Marian Klühspies
  • 15,824
  • 16
  • 93
  • 136