30

我认为多重继承在 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() {}
}

由于各种原因,我需要一个具有两种方法的接口。

4

5 回答 5

32

不允许实现的多重继承。不过,组件可以继承多个接口。

继承多个接口没有问题,因为您只是定义要实现的新方法签名。传统上被视为导致问题或至少是混乱的功能的多个副本的继承(例如,死亡的钻石)。

于 2012-11-14T23:51:08.200 回答
8

一个接口可以扩展一个或多个其他接口。您还可以在您的类中实现多个接口。这是合法的,因为接口只是合同 - 没有实现。您只是定义了一个类能够做什么的契约,而没有说明该类将如何做。

于 2012-11-14T23:54:59.313 回答
5

实现接口不是“继承”,而是在扩展类时。

实现接口用于声明一个类“看起来像”某物,而扩展类用于声明一个类“是”某物。

“看起来像”多个事物是可以的,但不能“成为”多个事物。


使用扩展多个接口的空接口作为将一组接口收集到单个接口以传达更广泛但可重用的 API 的一种方式并没有错。

于 2012-11-14T23:56:25.237 回答
1

试试这个,它需要 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 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;
                }
        }
        /************************************************************************************/

}
于 2015-01-20T13:28:39.287 回答
0

这个相关的问题中,杰伊提供了一个答案。区别在于指定实现与接口。

仅当两个函数具有相同名称时,才会出现实现问题。这是因为对于“我使用什么 f() 实现?”这个问题没有明显的选择。具有多种实现。

具有相同功能名称的两个接口不会出现此问题,因为它不需要进行此选择。相反,您只需要实现您自己的手头功能版本。

例如,我们可以看一个允许多重继承的对应物——C++。这个链接很好地解释了事情,并提供了一些代码/图像示例。需要注意的一件事是,由于您需要明确定义函数所属的类,因此您可以轻松地缓解 C++ 中的问题。

然而,在 Java 中,我们真的不必这样做(因为只有附加到对象的方法,如果你愿意的话),因此没有方法来确定调用的范围。我们必须引用父类的唯一选项是使用super关键字或使用static函数。因此,除非对系统进行额外的更改,否则在 Java 中将没有明确的选择来解决此问题,而收益甚微。

于 2012-11-15T00:07:55.267 回答