java支持"软"接口吗?

Rik*_*aaf 5 java interface mixins

请考虑以下情形:假设您创建了一个接口Foo:

public interface Foo {

    public void bar();

}
Run Code Online (Sandbox Code Playgroud)

并且说SomeOldClass某个库中有一个旧类要使用.它已经有了bar()方法,但没有明确实现Foo.

您已为所有实现的类别编写了以下代码Foo:

public <T extends Foo> T callBarOnThird(List<T> fooList){
    return fooList.get(2).bar();
}
Run Code Online (Sandbox Code Playgroud)

现在你想让它也适用SomeOldClass.您无权访问此类的源代码,因此无法对其进行修改.

有没有办法声明Foo或类似某种"软"接口,(因为在任何实现所有必需方法的类将被接受作为软接口的隐式实现)?如果没有,您将如何使用尽可能干净的代码解决这个问题?

Thi*_*ilo 5

不,不是的.

您必须提供一个适配器实例(有几种方法和工具可以帮助实现,但Java不会"隐式地"执行它).


小智 4

Java 是静态类型动态绑定的

动态绑定:这意味着方法签名与其实现之间的链接发生在运行时。例如。

例如

public interface MyInterface {

    void doStuff();

}

public class MyFirstImpl implements MyInterface {

   @Override
   public void doStuff() {
       // do some stuff here
   }

}

public class MySecondImpl implements MyInterface {

   @Override
   public void doStuff() {
       // do some stuff here
   }

}
Run Code Online (Sandbox Code Playgroud)

所以如果你有下一个片段

MyInterface test; // pointing to either MyFirstImpl or MySecondImpl 
test.doStuff();
Run Code Online (Sandbox Code Playgroud)

JVM 将在运行时确定doStuff从对象的运行时类型MyFirstImplMySecondImpl基于对象的运行时类型调用方法。

静态类型:这意味着 JVM 将在编译时检查是否有方法可以调用,无论实现如何。

例如:

public interface MyInterface {

    void doStuff();

}

public class MyFirstImpl implements MyInterface {

   // no override here
   public void doStuff() {
       // do some stuff here
   }

}

public class MySecondImpl implements MyInterface {

   // no override here
   public void doStuff() {
       // do some stuff here
   }

}
Run Code Online (Sandbox Code Playgroud)

所以如果你有下一个片段

MyInterface test; // pointing to either MyFirstImpl or MySecondImpl 
test.doStuff();
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨,因为它无法确保在编译时无论实现如何MyInterface都有一个doStuff方法可以调用(尽管在这种情况下,两个实现都MyInterface定义了一个doStuff方法)。

这可以确保您不会NoSuchMethodException在运行时获得 a ,例如,如果您要通过下一个实现。

public class MySecondImpl implements MyInterface {

   // no override here
   // no doStuff method

}
Run Code Online (Sandbox Code Playgroud)

这为语言增加了一些类型安全性,但代价是一些刚性(因为您能够比运行时更早地确定问题,因此您的反馈循环更短,代价是所有实现实际上都暴露了方法不能开箱即用)。

你应该如何重构你的代码:

在第三方库上创建一个包装器并从包装器中公开接口。

public interface Foo {

    void bar();

}

public class ThirdPartyFooWrapper implements Foo {

     private SomeOldClass oldClass;

     public ThordPartyFooWrapper (SomeOldClass oldClass){
          this.oldClass = oldClass;
     }

     @Override
     public void bar() {
         this.oldClass.bar();
     }

}
Run Code Online (Sandbox Code Playgroud)

然后,在您的代码中使用ThirdPartyFooWrapper而不是SomeOldClass.

希望这能回答您的问题!