java 是否支持 "Soft" 接口?

Does java support "Soft" interfaces?

考虑以下场景: 假设您创建了一个接口 Foo:

public interface Foo {

    public void bar();

}

并说某库中有一个旧的classSomeOldClass你要用。它已经有 bar() 方法,但没有显式实现 Foo.

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

public <T extends Foo> T callBarOnThird(List<T> fooList){
    return fooList.get(2).bar();
}

现在您希望它也适用于 SomeOldClass。您无权访问此 class 的源代码,因此无法修改它。

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

不,不是。

您必须提供一个适配器实例(有多种方法和工具可以提供帮助,但 Java 不会这样做 "implicitly")。

Thilos 答案的扩展。

你也可以使用装饰器来处理这个

public <T extends Foo> T callBarOnThird(List<T> fooList){
    return new BarDecorator(fooList.get(2)).bar();
}

在装饰器内部,您可以检查给定的对象是否是 Foo 的实例,然后进行相应的操作。

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
   }

}

所以如果你想要下一个片段

MyInterface test; // pointing to either MyFirstImpl or MySecondImpl 
test.doStuff();

JVM 会根据对象的运行时类型,在运行时天气决定从MyFirstImplMySecondImpl调用doStuff方法。

静态类型: 这意味着 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
   }

}

所以如果你想要下一个片段

MyInterface test; // pointing to either MyFirstImpl or MySecondImpl 
test.doStuff();

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

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

public class MySecondImpl implements MyInterface {

   // no override here
   // no doStuff method

}

这会以一些刚性为代价为语言增加了一些类型安全性(因为您能够比在运行时更早地确定问题,因此您有一个更短的反馈循环,代价是所有的场景这些实现实际上公开了无法开箱即用的方法。

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

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

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();
     }

}

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

希望这能回答您的问题!