【问题标题】:Java 8 Interface with default Methods not working when Jacoco Enabled启用 Jacoco 时,具有默认方法的 Java 8 接口不起作用
【发布时间】:2018-06-06 07:31:03
【问题描述】:

我们有一个带有默认方法的接口,我们在JavaKotlin 类中实现了该接口,并且我们为非默认方法提供了实现。

当我们在调试模式下运行(没有 testCoverageEnabled = true)并且应用按预期运行时。但是当我们在 testCoverageEnabled = true 的不同配置中运行时,应用程序崩溃并出现以下错误

java.lang.NoSuchMethodError: No static method $$triggerInterfaceInit()V in class Lcom/ui/viewholders/CAViewContract$$CC; or its super classes (declaration of 'ui.viewholders.CAViewContract$$CC' appears in /data/app/SMCXbiLYvHb1Kk08Kee__g==/base.apk)
    at home.c.CCFragment.<clinit>(Unknown Source:0)
    at home.HomePageCardProvider.getFragment(HomePageCardProvider.java:17)
    at home.HomeFragment.handleCardFragment(HomeFragment.java:172)

注意: 1. JaCoCo 版本:“0.8.0” 2. 操作系统:Android with minSdk 21

如果我们将 minSdk 更改为 24,使用 testCoverageEnabled = true 本身,它就可以工作。我们无法找出确切的问题。

【问题讨论】:

标签: java android java-8 kotlin jacoco


【解决方案1】:

如果您要调用的方法的default 实现在interface 中没有default 实现,而您的类显式地implements 它,则可能会出现此问题。 (但在interface基(父,超) interface 中有一个default 实现。

示例:假设这些定义:

class A implements DerivedInterface /*, ...*/ {
    @Override public void methodFromBaseInterface() {
        DerivedInterface.super.methodFromBaseInterface(); // Error:
            // NoSuchMethodError: No static method methodFromBaseInterface
    }
    // ...
}

interface DerivedInterface extends BaseInterface {
    // ... 
    // `methodFromBaseInterface` hasn't overriden here.
}

interface BaseInterface {
    default void methodFromBaseInterface() { /* ...*/ }
    // ...
}

然后执行:

A a = new A();
a.methodFromBaseInterface(); // This cause above error!

你在提到的地方得到一个错误!

(附注:您可能需要在DerivedInterface 中定义至少一个方法以避免在运行时获得NoClassDefFoundError!)


这类似于一个错误! 我们使用了super 关键字。为什么期待static方法?!!还有一点,上面的代码没有任何问题,你可以在任何Java 8兼容的环境中运行,没有任何问题!

我认为问题与 Android 平台对 Java 8 语言 API 的不完全支持有关

Android Studio 3.0 及更高版本支持所有 Java 7 语言功能和Java 8 语言功能的子集,因平台版本而异

专门查看that page中的Java 8 Language APICompatible minSdkVersion表:

java.lang.FunctionalInterface:API 级别 24 或更高。


我找到的解决方法:

  1. 如果您有权访问DerivedInterface 的定义,只需覆盖methodFromBaseInterface 并将其显式委托给其super 接口:

    interface DerivedInterface extends BaseInterface {
        @Override default void methodFromBaseInterface() {
            BaseInterface.super.methodFromBaseInterface();
        }
        // ...
    }
    
  2. 定义实现BaseInterface 的中间class 并从中派生A。然后运行methodFromBaseInterface间接抛出中间class

    class MiddleClass /*extends B*/ implements BaseInterface {}
    
    class A extends MiddleClass implements DerivedInterface {
        @Override public void methodFromBaseInterface() {
            super.methodFromBaseInterface(); // Indirectly from `MiddleClass`
        }
        // ...
    }
    

    注意:如果您的 A 类以前有一个名为 Bsuper,请取消注释 /*extends B*/

【讨论】:

    猜你喜欢
    • 2019-04-02
    • 2017-09-25
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 2018-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多