众所周知,多个interfaces可以用Java实现.他们的实施顺序是否重要?我的意思是,正在实施B,C与C,B相同Java 8吗?我的测试显示顺序确实很重要 - 但任何人都可以解释这背后的逻辑吗?
public interface A {
public default void display() {
System.out.println("Display from A");
}
}
public interface B extends A {
public default void display() {
System.out.println("Display from B");
}
}
public interface C extends A {
public void display();
}
public interface D extends B, C {
}
Run Code Online (Sandbox Code Playgroud)
上面的代码工作正常.如果我将订单更改B, C为C, B,则会出错:The default method display() inherited from B conflicts with another method inherited from C.
public …Run Code Online (Sandbox Code Playgroud) public interface Table<T> {
@Overrride
default boolean equals(Object other) {
//do something and return true/false
}
}
Run Code Online (Sandbox Code Playgroud)
为什么上面的代码有编译错误"java:默认方法在接口表中等于覆盖java.lang.Object的成员"?我们不能使用接口默认方法覆盖hashCode和equals方法,大概我在同一个接口中有方法来确定实现这个接口的对象是否相等?
在我的应用程序中,我遇到一个问题,当类中的getter仅在接口中默认(Java 8特性)时,结果没有Java Beans属性.即正常方法调用它只是作为一种标准方法,但对于通过"属性"访问它突然表现不同......
这是一个测试用例:
import java.beans.Introspector;
import java.util.Arrays;
import java.util.stream.Collectors;
import org.apache.commons.beanutils.PropertyUtils;
public class test
{
public static void main (String[] arguments) throws Exception
{
// Normal language-level invocation, works fine.
System.out.println (new Bean1 ().getFoo ());
System.out.println (new Bean2 ().getFoo ());
// Printing Java Beans properties; Bean2 doesn't have 'foo' property...
System.out.println (Arrays.stream (Introspector.getBeanInfo (Bean1.class).getPropertyDescriptors ())
.map ((property) -> property.getName ())
.collect (Collectors.joining (", ")));
System.out.println (Arrays.stream (Introspector.getBeanInfo (Bean2.class).getPropertyDescriptors ())
.map ((property) -> property.getName ())
.collect (Collectors.joining (", ")));
// …Run Code Online (Sandbox Code Playgroud) 在Java 8中,如果我有两个具有不同(但兼容)返回类型的接口,则反射告诉我两个方法中的一个是默认方法,即使我实际上没有将该方法声明为默认方法或提供方法体.
例如,请使用以下代码段:
package com.company;
import java.lang.reflect.Method;
interface BarInterface {}
class Bar implements BarInterface {}
interface FooInterface {
public BarInterface getBar();
}
interface FooInterface2 extends FooInterface {
public Bar getBar();
}
class Foo implements FooInterface2 {
public Bar getBar(){
throw new UnsupportedOperationException();
}
}
public class Main {
public static void main(String[] args) {
for(Method m : FooInterface2.class.getMethods()){
System.out.println(m);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Java 1.8生成以下输出:
public abstract com.company.Bar com.company.FooInterface2.getBar()
public default com.company.BarInterface com.company.FooInterface2.getBar()
Run Code Online (Sandbox Code Playgroud)
这看起来很奇怪,不仅因为两种方法都存在,而且因为其中一种方法突然而且莫名其妙地变成了默认方法.
尽管两种方法具有相同的签名,但在Java 7中运行相同的代码会产生一些不太意外的情况,尽管仍然令人困惑:
public …Run Code Online (Sandbox Code Playgroud) Java 8接口默认方法与抽象类中的非抽象方法 - 两者之间是否存在任何差异(除了iface的类别,可见性等)
不是Java中的默认方法,这意味着它违背了Java多年来所宣传的本质?!
我有以下情况:
class C {
static void m1() {}
}
interface I {
default void m1() {}
}
//this will give compilation error : inherited method from C cannot hide public abstract method in I
class Main extends C implements I {
}
Run Code Online (Sandbox Code Playgroud)
以下是我的问题:
我知道实例方法将覆盖默认方法,但是如果类中的静态方法与Interface中的默认方法具有相同的签名呢?
如果静态方法m1()在class C将公共那么编译错误将是:
静态方法m1()与I.中的抽象方法冲突
因此,当访问修饰符是默认值时,它试图隐藏,当它是公共时,它是冲突的.为什么会有这种差异?它背后的概念是什么?
我已经在SO上阅读了关于实现接口和抽象类的多篇帖子.我特别想找到一个我想链接的地方 - 链接 - 接口与默认方法vs抽象类,它涵盖了同样的问题.作为公认的答案,建议在可能的情况下使用接口的默认方法.但是这个答案下面的评论说"这个功能对我来说更像是黑客"解释了我的问题.
引入了默认方法以使接口的实现更加灵活 - 当接口发生更改时,实现类中不一定需要(重新)编写代码.因此,使用接口的默认方法只是为了实现所有实现类中的方法 - 引用:"感觉更像是对我的黑客攻击".
课程概述:
结合这些:
水是物品并实施消耗品; Stone也是一个项目,并没有实现消耗品.
我想实现一个所有项目必须实现的方法.因此,我在类Item中声明了签名.
protected abstract boolean isConsumable();
//return true if class implements (or rather "is consumable") Consumable and false in case it does not
Run Code Online (Sandbox Code Playgroud)
快速编辑:我知道instanceof可以解决这个特定的例子 - 如果可能的话,想一个更复杂的例子,这使得有必要首先实现该方法.(感谢Sp00m和Eugene)
现在我有几个选择:
- 在Item的每个子类中手动实现该方法(在扩展应用程序时绝对不可能).
如上所述,当缩放应用程序时,这将是不切实际或非常低效的.
- 在接口内部实现方法作为默认方法,因此Consumable类已经实现了超类Item所需的方法.
这是其他帖子推荐的解决方案 - 我看到以这种方式实现它的优势:
引用 - "关于这个新功能的好处是,在你被迫使用抽象类来实现方便方法之前,从而将实现者限制为单继承,现在你可以只使用接口和一个非常干净的设计最少的实施工作强加给程序员." 链接
但在我看来,我在介绍中提到的默认方法的最初想法似乎仍然是矛盾的.此外,在扩展应用程序并引入更多共享相同实现的方法(作为示例方法isConsumable())时,接口将实现几个默认方法,这与未实现实际方法的接口的想法相矛盾.
- 引入子超类而不是接口 - 例如类Consumable作为Item的抽象子类和Water的超类.
它提供了为Item(示例isConsumable() //return false:)中的方法编写默认大小写的机会,然后在子超类中重写它.此处出现的问题:在扩展应用程序并引入更多子超类(作为Consumable类)时,实际的Items将开始扩展多个子超类.这可能不是一件坏事,因为它也必须对接口做同样的事情,但它使继承树变得复杂 - 示例:一个项目现在可能扩展子类别ALayer2,它是ALayer1的子超类,它扩展了Item(layer0) . …
在java 8中我有这样的东西:
package test;
public class SimpleFuncInterfaceTest {
public static void carryOutWork(AFunctionalInterface sfi){
sfi.doWork();
}
public static void main(String[] args) {
carryOutWork(() -> System.out.println("Do work in lambda exp impl..."));
AImplementor implementsA = new AImplementor();
//carryOutWork(() -> implementsA.doWork());
BImplementor implementsB = new BImplementor();
carryOutWork(() -> implementsB.doWork());
}
}
@FunctionalInterface
interface AFunctionalInterface {
public void doWork();
default public void doSomeWork(){
System.out.println("FOO");
}
}
@FunctionalInterface
interface BFunctionalInterface extends AFunctionalInterface {
@Override
default public void doSomeWork(){
System.out.println("BAR");//Unreachable in same object?
}
}
class AImplementor …Run Code Online (Sandbox Code Playgroud) 考虑下面的例子,
public class Testing extends SupCls implements Intf {
public static void main(String[] args) {
new Testing().test();
}
}
class SupCls {
public void test() {
System.out.println("From SupCls");
}
}
interface Intf {
public default void test() {
System.out.println("From Intf");
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,SupCls类和Intf接口之间没有任何联系.但两者都定义了一种常用方法.
而Testing类的扩展SupCls和实现Intf.
所以,当我在输出test()上调用方法时Testing,
From SupCls
Run Code Online (Sandbox Code Playgroud)
我认为这是有道理的,因为从类扩展应该比从接口实现更高的优先级.
但是eclipse报告不然,如下面的屏幕截图所示.
我坚信这是Eclipse中的一个错误.
但在假设之前,是否在JLS中定义并记录了此行为?或者还有其他什么来定义这种行为?
编辑:Eclipse版本是Mars Release(4.5.0),如果重要的话.
在Java 8中,除了需要在具体类中实现的声明之外,我们还可以为接口中的方法提供默认实现.
在接口中使用默认方法是一个好的设计还是最佳实践,或者Java 8是否只是为了在旧的API上提供更多支持?我们应该从新的Java 8项目中使用默认方法开始吗?
请帮我详细了解这里的优秀设计.
default-method ×10
java ×10
java-8 ×8
interface ×3
inheritance ×2
eclipse ×1
javabeans ×1
return-type ×1