Множественное наследование на интерфейсах Java

Я думал, что множественное наследование всегда было незаконным в Java, но этот код компилируется:

public interface A {
  void a();
}

public interface B {
  void b();
}

public interface AB extends A, B {
}

Будет ли пустой интерфейс, такой как AB, рассматриваться как плохая практика? Есть ли способ достичь чего-то подобного, избегая пустого интерфейса (используя дженерики или иначе)?

Примечание. Я не спрашиваю, как имитировать множественное наследование через интерфейсы. Я понимаю, что могу сделать следующее:

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

По разным причинам мне нужен интерфейс, который имеет оба метода.

Ответ 1

Не допускается множественное наследование реализаций. Компоненты могут наследовать несколько интерфейсов.

Наследование нескольких интерфейсов не является проблематичным, поскольку вы просто определяете новые сигнатуры методов, которые должны быть реализованы. Это наследование множества копий функциональности, которые традиционно рассматриваются как вызывающие проблемы или, по крайней мере, путаница (например, алмаз смерти).

Ответ 2

Интерфейс может распространять один или несколько других интерфейсов. Вы также можете реализовать более одного интерфейса в своих классах. Это законно, потому что интерфейс - это только контракт - реализации нет. Вы просто определяете контракт для того, что класс может сделать, не говоря ничего о том, как класс будет это делать.

Ответ 3

Реализация интерфейсов не является "наследованием", то есть когда вы расширяете класс.

Реализация интерфейсов используется, чтобы объявить, что класс "выглядит", а расширенные классы используются, чтобы объявить, что класс "является" чем-то.

Это нормально, чтобы "выглядеть" несколькими вещами, но не "быть" несколькими вещами.


Нет ничего плохого в том, что у вас есть пустые интерфейсы, которые расширяют несколько интерфейсов, как способ сбора набора интерфейсов в один интерфейс для передачи более широкого, но повторно используемого API.

Ответ 4

В этот связанный вопрос, Джей дает ответ на этот вопрос. Разница заключается в определении реализации по сравнению с интерфейсом.

Проблема с реализацией происходит только тогда, когда две функции имеют одинаковое имя. Это связано с тем, что нет очевидного выбора в вопросе "Какую реализацию f() я использую?" с несколькими реализациями.

Проблема не возникает с двумя интерфейсами одного и того же имени функции, потому что не нужно делать этот выбор. Скорее всего, вам просто нужно реализовать свою собственную версию функции.

В качестве примера мы можем посмотреть на аналог, что разрешает множественное наследование - С++. Эта ссылка хорошо объясняет и предоставляет примеры кода/изображения. Одно замечание состоит в том, что, поскольку вам необходимо явно указать класс, к которому принадлежит функция, в любом случае вы можете легко устранить проблему на С++.

В Java, однако, мы действительно никогда не должны этого делать (поскольку есть только методы, которые привязаны к объектам, если вы это сделаете), в результате не существует метода для охвата вызова. Единственными параметрами, которые мы должны относить к родительскому классу, является использование ключевого слова super или с помощью функции static. В результате не было бы ясного варианта разрешить это на Java, запретив дополнительные изменения в системе, для небольшого выигрыша.

Ответ 5

Попробуйте, для этого требуется Java 8.

Просто скопируйте и сохраните файл в Stateful.java.

Он также доступен здесь: 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 [email protected]{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;
                }
        }
        /************************************************************************************/

}