我认为多重继承在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() {}
}
由于各种原因,我需要一个具有两种方法的接口。
答案 0 :(得分:27)
不允许实现的多重继承。但是,组件可以继承多个接口。
继承多个接口不成问题,因为您只是定义要实现的新方法签名。它是多个功能副本的继承,传统上被视为导致问题,或者至少是混淆(例如,diamond of death)。
答案 1 :(得分:8)
接口可以扩展一个或多个其他接口。您还可以在类中实现多个接口。这是合法的,因为接口只是合同 - 没有实现。你只是简单地定义了一个类能够做什么的合同,而没有说出关于类如何做的事情。
答案 2 :(得分:4)
实现接口不是“继承”,即扩展类时。
实现接口用于声明类“看起来像”某事,而扩展类用于声明类“是”某事。
“看起来像”多件事情是可以的,但不是“成为”多件事。
使用扩展多个接口的空接口作为将一组接口收集到单个接口中以传达更广泛但重用的API的方式没有任何问题。
答案 3 :(得分:0)
在this related question中,Jay为此提供了答案。区别在于指定实现与接口。
仅当两个函数具有相同名称时才会出现实现问题。这是因为“我使用f()的实现是什么?”这个问题没有明显的选择。有多个实现。
具有相同功能名称的两个接口不会发生此问题,因为它不需要进行此选择。相反,您只需要实现自己的函数版本。
作为一个例子,我们可以看一下does allow multiple inheritance - C++的对手。此链接可以很好地解释,并提供一些代码/图像示例。需要注意的一点是,由于您需要明确地确定函数所属的类的范围,因此您可以轻松地缓解C ++中的问题。
然而,在Java中,我们真的不必这样做(因为只有附加到对象的方法,如果你愿意的话),因此没有一个方法来调整范围。我们必须引用父类的唯一选项是使用super
关键字,或使用static
函数。因此,在Java中没有明确的选择来解决这个问题,除非对系统进行额外的更改,否则收益甚微。
答案 4 :(得分:0)
试试这个,它需要Java 8.
只需将文件复制并保存到Stateful.java中即可。
/**************************************************************************************************************************************
* 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;
}
}
/************************************************************************************/
}