通用类型Java 8的调用方法

时间:2017-01-10 20:50:13

标签: java function generics

我有一个function接受一个generic类型

的参数
  

public< T扩展了SomeA> String foo(T t){...}

现在...... SomeA包含一系列可以调用的方法,例如baz1()baz2()baz3()等等。

现在,请点击

  1. 将传递给T的变量foo(T t)将是SomeBSomeC的实例,其中SomeB extends SomeA和{{ 1}}。

  2. SomeC extends someASomeB都包含方法SomeC,返回glop(...)然而SomeD不是在glop(...)

  3. 我希望能够传递SomeA,以便它接受foo(T t)SomeB,但是,我需要调用SomeC(例如, )

  4. E.g。

    glop(...)

    我不想单独为public < T extends SomeA > String foo(T t) { return t.glop().methodInsideOfSomeD().toString(); } foo(即SomeB SomeC)实施fooSomeB。我希望能够将此方法传递给提供fooSomeCSomeB的函数(或者更好的包含方法SomeC的任何内容)。

    问题:我无法更改glop(...)SomeB的实现或声明,因为它们位于我无法控制的库中。因此,我不能让它们都实现一些提供SomeC的接口。

    我只是运气不好吗?

2 个答案:

答案 0 :(得分:2)

请注意,使用您描述的签名定义泛型方法几乎没有意义。如果类型参数T仅用作一个或多个参数的类型,那么您也可以通过手动擦除它来简化操作:

public String foo(SomeA t) { /* ... */ }

在任何情况下,您至少都有符合您要求的替代方案:

  1. 将一个foo()替换为两个重载的,一个类型参数以SomeB为界,另一个类型参数以SomeC为界。这假设您没有SomeA的其他子类型为此目的担心,这似乎是合理的,因为SomeA没有glop()

  2. foo()的实施中,使用instanceof运算符(或Class.isInstance())来识别SomeBSomeC的实例,并处理适当的。

  3. 使用foo()中的反射来确定参数的类是否提供了具有预期签名的可访问glop(),如果是,则反复调用它。

    < / LI>

    这些都不要求您以任何方式修改SomeASomeBSomeC。我知道你说你不想做(1),但它很干净,很容易。你应该考虑一下。

      

    我希望能够将此方法传递给提供包含方法glop(...)的任何内容的函数,甚至更好。

    那可能是(3),也许参数类型改为Object,但我怀疑你真的想要那样。反思很混乱,通常应该避免。

答案 1 :(得分:1)

根据我的理解,您将不得不复制该方法,但您可以通过分解公共部分来重用代码:

public < T extends SomeB > String foo(T t) {return fooX(t.glop());}
public < T extends SomeC > String foo(T t) {return fooX(t.glop());}

采用glop()

结果的新方法
private String fooX(SomeD globResult) {
  return globResult.methodInsideOfSomeD().toString();
}

我不知道为什么您无法更改SomeA以使用默认实现(或方法)添加glob()方法,但是如果您可以为您添加界面SomeB / SomeC课程,比如ProviderOfSomeD,你可以这样做:

public < T extends SomeA & ProviderOfSomeD> String foo(T t) {return fooX(t.glop());}

请注意,您可以使用此功能进行限制。

另一种Java 8方式(不需要任何更改):

public String foo(final Supplier<? extends SomeD> t) {return fooX(t.get());}

// calling them:
SomeB b = ...;
SomeC b = ...;
foo(b::glop);
foo(c::glop);