首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >我试图转换使用Java8语言特性的两个模块,如何模拟静态/默认方法行为?

我试图转换使用Java8语言特性的两个模块,如何模拟静态/默认方法行为?
EN

Stack Overflow用户
提问于 2017-05-09 22:40:58
回答 2查看 73关注 0票数 1

我的任务是迁移两个独立的模块,以兼容Java 7编译和运行时。我想知道我是否把所有的事情都考虑进去了(也就是说,将来会有很多副作用,限制等等)。

这些模块称为ModuleA和ModuleB,结构如下:

代码语言:javascript
复制
ModuleA            <- Runtime Library
   \-pack1      <- This contains ~15 interfaces, ~3 layers of inheritance, and occasionally static/default methods 
   \-pack2      <- This contains some standard implementations of interfaces in package1

ModuleB            <- Main app. Depends on ModuleA
   \-main          <- Classes here call static/default ModuleA.package1.* interface methods a lot

ModuleB可以定期更改,而ModuleA是专有/内部API,不太可能更改。将源代码转换为Java 7兼容性是一个一直给我带来麻烦的过程。

我最初计划这样做的方法是在每个接口中创建一个静态内部类,并在内部类中迁移静态和默认方法,然后更改所有这些方法( static )。我将在更改签名/实现后标记(前)默认方法,将实例添加为参数列表中的第一个参数,然后添加注释@Default (因此我将知道如何在ModuleB中转换实现)。所以这个:

代码语言:javascript
复制
    interface Foo {

        void doFoo(String bar);

        default String toFancyString() {
            return this.toString() + "called from a default method";
        }

        static int getFooDefault() {
            return 0xCAFEBABE;
        }
    }

将改为:

代码语言:javascript
复制
interface Foo {
    void doFoo(String bar);

    final class Util {

        @Default
        static String toFancyString(Foo impl) {
            return impl.toString() + "called from a default method";
        }
        static int getFooDefault() {
            return 0xCAFEBABE;
        }
    }
}

在更改两个ModuleA包之后,我会将ModuleB (在编译时)更改为等效于更改以下内容:

代码语言:javascript
复制
int i = foo.getFooDefault() + 1;
Foo f = bar -> System.out.println(bar);
String fancyString = f.toFancyString();

对此:

代码语言:javascript
复制
int i = Foo.Default.getFooDefault() + 1;
Foo f = // anonymous class bloat here
String fancyString = Foo.Default.toFancyString(f);

我想知道的是:

  • 如何在更改ModuleA.package1时模拟接口继承?由于Util类中的方法都是静态的,所以我考虑将所有静态方法添加到存在超类方法的子类中,并从子类静态方法手动调用最近的上链静态方法,但是可能有一个更简单的解决方案。
  • 如果我自动化了第二部分(ModuleB -代码可能经常更改),这会不会出现这样的情况呢?

代码行/复杂性并不重要,因为我可以编写大部分源转换的脚本。我的目标只是在JRE7中运行时能够产生与在8中相同的精确输入/输出,而无需使用任何反射/鸭子类型的。(而且,我只担心静态/默认问题,而不是任何新的JDK8 API)

EN

回答 2

Stack Overflow用户

发布于 2017-05-10 13:48:58

将jdk-8迁移到jdk-7,在接口上使用默认方法/静态方法。您可以用抽象类替换接口。然后,使用迁移模块的其他模块不需要修改。例如:

代码语言:javascript
复制
abstract class Foo {

    public abstract void doFoo(String bar);

    public String toFancyString() {
        return this.toString() + "called from a default method";
    }

    public static int getFooDefault() {
        return 0xCAFEBABE;
    }
}

但是,当您使用java 代理 api时,引入抽象类并将所有静态方法提取到抽象类中还有另一个原因。然后,让所有已实现Foo的类扩展AbstractFoo,例如:

代码语言:javascript
复制
interface Foo {
    void doFoo(String bar);

    String toFancyString();
}

abstract class AbstractFoo implements Foo {
    public String toFancyString() {
        return this.toString() + "called from a default method";
    }

    static int getFooDefault() {
        return 0xCAFEBABE;
    }
}

class SimpleFoo extends AbstractFoo {
    @Override
    public void doFoo(String bar) {/*todo*/}
}

备注:其他模块在第二种方法中调用静态方法时需要修改,因为静态方法所在的位置发生了更改。

票数 2
EN

Stack Overflow用户

发布于 2017-05-09 23:27:52

我相信您已经知道,在Java8中引入的接口中的@FunctionalInterface和默认实现,在此之前,interface...this中没有任何实现都必须在任何实现中完成。一般说来,我还是会说这是一种糟糕的做法。我的想法是,如果我想将方法添加到已经存在的接口中,而不是破坏所有正在使用的方法(比如列表接口上的forEach )。

话虽如此,我不知道是否有一条笔直的路要走。您可以做一个已经实现了这些的抽象类,但是只能从一个抽象类继承,所以这可能不起作用,或者静态方法described...but将继承从水中吹出。

@FunctionalInterface很简单,它只是强制在编译时接口中只有一个非默认方法。只要删除注释,Java 7就可以使用了。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/43880947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档