31

I thought multiple inheritance was always illegal in Java, but this code compiles:

public interface A {
  void a();
}

public interface B {
  void b();
}

public interface AB extends A, B {
}

Would having an empty interface such as AB be considered a bad practice? Is there a way to achieve something similar while avoiding the empty interface (using generics or otherwise)?

Note: I'm not asking how to simulate multiple inheritance via interfaces. I realize I could do the following:

public class AbImpl implements A, B {
  public void a() {}
  public void b() {}
}

For various reasons I need an interface that has both methods.

Jacob Wallace
  • 887
  • 2
  • 12
  • 24
  • 1
    Your first example provides a shortcut that is basically equivalent to the second example. There is nothing wrong with doing this. – Code-Apprentice Nov 14 '12 at 23:50

5 Answers5

33

Multiple inheritance of implementations is not allowed. Components can inherit multiple interfaces, though.

Inheriting multiple interfaces isn't problematic, since you're simply defining new method signatures to be implemented. It's the inheritance of multiple copies of functionality that is traditionally viewed as causing problems, or at the very least, confusion (e.g., the diamond of death).

Dave Jarvis
  • 30,436
  • 41
  • 178
  • 315
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 2
    This answer is outdated: Java 8 allows [multiple inheritance of method implementations](https://www.programcreek.com/2014/12/default-methods-in-java-8-and-multiple-inheritance/) in interfaces. – Anderson Green May 14 '21 at 17:04
9

An interface can extend one or more other interfaces. You can also implement more than one interface in your classes. It is legal because interface is only contract - there is no implementation. You're simply defining a contract for what a class is able to do, without saying anything about how the class will do it.

Maciej Ziarko
  • 11,494
  • 13
  • 48
  • 69
6

Implementing interfaces is not "inheritance", which is when you extend a class.

Implementing interfaces is used to declare that a class "looks like" something, whereas extending classes is used to declare that a class "is a" something.

It's OK to "look like" multiple things, but not "be" multiple things.


There's nothing wrong with having empty interfaces that extend multiple interfaces as a way of collecting a set of interfaces into a single interface to convey a broader, but reused, API.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
1

Try this, it requires Java 8.

Just copy and save the file into Stateful.java.

It is available here as well: https://bitbucket.org/momomo/opensource/src/e699d8da450897b5f6cd94a5d329b3829282d1d6/src/momomo/com/Stateful/Stateful.java?at=default

    /**************************************************************************************************************************************
 * Copyright(C) 2014, Mo Enterprises Inc.                                                                                             *
 * All rights reserved.                                                                                                               *
 * Mo Enterprises Inc Opensource License 'MoL1'.                                                                                      *
 *                                                                                                                                    *
 * (1) Use of this source code, wether identical, changed or altered is allowed, for both commercial and non-commercial use.          *
 *                                                                                                                                    *
 * (2) This source code may be changed and altered freely to be used only within your entity/organisation, given that a notice of all *
 *     changes introduced are listed and included at the end of a copy of this exact copyright notice, including the name and date of *
 *     the entity/organization that introduced them.                                                                                  *
 *                                                                                                                                    *
 * (3) The redistribution or publication to the public of this source code, if changed or altered, is striclty prohibited using any   *
 *     medium not owned, and/or controlled by Mo Enterprises Inc unless a written consent has been requested and recieved by          *
 *     representatives of Mo Enterprises Inc.                                                                                         *
 *                                                                                                                                    *
 * (4) The distribution of any work to the public derived through the use of this source code, wether identical, changed or altered,  *
 *     is allowed, as long as it in full compliance of (3).                                                                           *
 *                                                                                                                                    *
 * (5) Mo Enterprises Inc considers the techniques and design patterns employed in this source code as unique and making the          *
 *     redistribution of this source code with altered names, and/or a rearrangement of code as a severe breach of the copyright law  *
 *     and this license. Mo Enterprises Inc reserves all rights to puruse any and all legal options.                                  *
 *                                                                                                                                    *
 * (6) All copies of this source code, wether identical, changed/altered must include this entire copyright notice, list all changes  *
 *     made including the name and date of the entity/organization that introduced them, as wel as the following disclaimer:          *
 *                                                                                                                                    *
 *     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND                                                *
 *     ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED                                                  *
 *     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE                                                         *
 *     DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR                                                *
 *     ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES                                                 *
 *     (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;                                                   *
 *     LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND                                                    *
 *     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT                                                     *
 *     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS                                                  *
 *     SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                                   *
 *                                                                                                                                    *
 * Please contact us on opensource@{at}momomo.com if you have an improvement to this source code you'd like to contribute.            *
 * We'll make sure to include your name and/or organisation as a contributor if accepted.                                             *
 **************************************************************************************************************************************/   

import java.util.IdentityHashMap;
import java.util.Map;

/**
 * @Author Mo. Joseph
 *
 * Consider memory leakage usage.
 * None of the public methods below should be used outside of the interface extending Stateful!
 */
@SuppressWarnings("unchecked")
public interface Stateful {
        /**
         * @Private access only! Strict enforcement, otherwise risks for memomry leaks!
         */
        static final Map<Stateful, IdentityHashMap<Class<State>, State>> STATES = new WeakIdentityHashMap<>( );

        /**
         * @Protected access only! Strict enforcement, otherwise risks for memomry leaks!
         *
         * Note, this method can not be generified!
         * If so, then it will conflict when a class implements several Stateful interfaces.
         */
        default <Y extends Stateful, T extends State<Y>> T $(Class<T> clazz) {
                synchronized (this) {
                        IdentityHashMap<Class<State>, State> map = STATES.get(this);
                        if ( map == null ) {
                                STATES.put(this, map = new IdentityHashMap<>() );
                        }

                        State state = map.get(clazz);
                        if (state == null) {
                                try {
                                        map.put(cast(clazz), state = clazz.newInstance() );
                                } catch (Throwable e) {
                                        throw new RuntimeException(e);
                                }
                        }
                        return (T) state;
                }
        }

        /**
         * @Protected access only! Strict enforcement, otherwise risks for memomry leaks!
         * May only be extended from within an interface that implements Stateful.
         */
        static interface State<Y extends Stateful> {}

        /**
         * @Private
         * Util method for casting used here. Simple casting won't work for some reason.
         */
        static <T>T cast(Object obj){
                return (T) obj;
        }



        /*******************************************************************************
         * Example code below:
         *******************************************************************************/
        public static void main(String[] args) {
                Person mo = new Person();
                mo.setName("Mo. Joseph");
                mo.setStreet("Mansion Street 1");
                System.out.println(mo.getName());
                System.out.println(mo.getStreet());

                Pet garfield = new Pet ();
                garfield.setName("Garfield");
                System.out.println(garfield.getName());

                Person santa = new Person();
                santa.setName("Santa");
                santa.setStreet("North Pole Street 1");
                System.out.println(santa.getName());
                System.out.println(santa.getStreet());

                mo.setName("mo");
                System.out.println(mo.getName());
                System.out.println(santa.getName());
                System.out.println(garfield.getName());
                System.out.println(santa.getStreet());
        }

        public static class Person implements Named, Address {

        }

        public static class Pet implements Named {

        }

        public static interface Named extends Stateful {
                static class State implements Stateful.State<Named> {
                        private String name;
                }

                public default void setName(String name) {
                        $(State.class).name = name;
                }

                public default String getName() {
                        return $(State.class).name;
                }
        }

        public static interface Address extends Stateful {
                static class State implements Stateful.State<Address> {
                        private String street;
                }

                public default void setStreet(String street) {
                        $(State.class).street = street;
                }

                public default String getStreet() {
                        return $(State.class).street;
                }
        }
        /************************************************************************************/

}
mjs
  • 21,431
  • 31
  • 118
  • 200
0

In this related question, Jay provides an answer to this. The difference is specifying the implementation versus the interface.

The issue with the implementation only occurs when two functions have the same name. This is because there is no obvious choice to the question "What implementation of f() do I use?" with multiple implementations.

The issue does not occur with two interfaces of the same function name because it does not need to make this selection. Rather, you are just required to implement your own version of the function at hand.

As an example, we can look at a counterpart that does allow multiple inheritance - C++. This link explains things well, and provides some code/image examples. One thing to notice is that since you are required to explicitly scope what class a function belongs to anyway, you can easily mitigate the issue in C++.

In Java however, we really never have to do this (since there are only methods which are attached to objects, if you will), As a result don't have a method to scope the call. The only options we have to refer to a parent class is by using the super keyword, or by use of a static function. As a result, there would be no clear option to resolve this in Java, barring additional changes to the system, for little gain.

Community
  • 1
  • 1
pseudoramble
  • 2,541
  • 22
  • 28