简体   繁体   English

Java接口上的多重继承

[英]Multiple inheritance on Java interfaces

I thought multiple inheritance was always illegal in Java, but this code compiles: 我认为多重继承在Java中总是非法的,但是这段代码编译:

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? AB这样的空接口会被视为不良做法吗? 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. 由于各种原因,我需要一个具有两种方法的接口。

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 (eg, the diamond of death ). 它是多个功能副本的继承,传统上被视为导致问题,或者至少是混乱(例如, 死亡钻石 )。

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. 你只是简单地定义了一个类能够做什么的合同,而没有说出类将如何做到这一点。

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. 使用扩展多个接口的空接口作为将一组接口收集到单个接口中以传达更广泛但重用的API的方式没有任何问题。

Try this, it requires Java 8. 试试这个,它需要Java 8。

Just copy and save the file into Stateful.java. 只需将文件复制并保存到Stateful.java中即可。

It is available here as well: https://bitbucket.org/momomo/opensource/src/e699d8da450897b5f6cd94a5d329b3829282d1d6/src/momomo/com/Stateful/Stateful.java?at=default 它也可以在这里找到: 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;
                }
        }
        /************************************************************************************/

}

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?" 这是因为“我使用f()的实现是什么?”这个问题没有明显的选择。 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++ . 作为一个例子,我们可以看一下允许多重继承的对应物--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++. 需要注意的一点是,由于您需要明确地确定函数所属的类的范围,因此您可以轻松地缓解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. 但是在Java中,我们真的不必这样做(因为只有附加到对象的方法,如果你愿意的话),因此没有一个方法来调整范围。 The only options we have to refer to a parent class is by using the super keyword, or by use of a static function. 我们必须引用父类的唯一选项是使用super关键字,或使用static函数。 As a result, there would be no clear option to resolve this in Java, barring additional changes to the system, for little gain. 因此,在Java中没有明确的选择来解决这个问题,除非对系统进行额外的更改,否则收益甚微。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM