如何将泛型方法引用作为参数传递



我想将泛型方法引用作为java方法中的参数传递。

仅举一个例子,我准备了一些摘要

public abstract class AbstractFoobar{
    abstract String getLiteral();
}

以及它扩展的 2 个类。类具有字符串参数构造函数。

public class Bar extends AbstractFoobar{
    String literal;
    public Bar(String literal) { this.literal = literal; }
    public String getLiteral() { return literal; }
}
public class Foo extends AbstractFoobar{
    String literal;
    public Foo(String literal) { this.literal = literal; }
    public String getLiteral() { return literal; }
}

我有一个简单的通用方法,可以创建对象的新实例。创建基于函数创建器参数

public <T extends AbstractFoobar> T foo(T foobar, Function<String, T> creator) {
    return creator.apply("foo" + foobar.getLiteral());
}

当使用特定方法引用 Bar::new 执行方法 foo 时,此示例完美运行。

@Test
void test()
    Bar bar = new Bar("bar");
    Bar foobar = foo(bar, Bar::new);
    assertEquals(Bar.class, foobar.getClass());
    assertEquals("foobar", foobar.getLiteral());
}

但是我不知道如何通过包装器方法fooGenerator传递引用方法

public <T extends AbstractFoobar> T fooGenerator(T foobar) {
    //#1 return foo(foobar, T::new);
    //#2 return foo(foobar, foobar.getClass().getConstructor(String.class));        
}

#1 编译器无法实例化类型 T

#2 方法 foo(..., Function<>( 不适用于参数构造函数<>

关于 Java 泛型的一个非常重要但从未被充分强调的观点是,它们只是避免编写显式强制转换的一种奇特方法。他们不多不少。

所以,如果你不会写:

public AbstractFoobar fooGenerator(AbstractFoobar foobar) {
    return foo(foobar, /* something here, involving AbstractFoobar and casts */::new);
}
// Call site
Bar foobar = (Bar) foo(bar);

那么你就不能用泛型来做到这一点。而且没有这样的事情,因为构造函数不参与继承:AbstractFoobar::new会创建一个AbstractFoobar实例(如果它可以实例化(,而不是子类。

对于您当前的AbstractFoobar定义,除了使用显式参数直接调用foo之外,您再无所不用其极了。


使用单个参数执行此操作的唯一方法是AbstractFoobar上有一个工厂方法,例如

public abstract class AbstractFoobar<A extends AbstractFoobar<A>> {
    // ...
    abstract A newInstance(String arg);
}
public class Bar extends AbstractFoobar<Bar> {
    // ...
    Bar newInstance(String arg) { return new Bar(arg); }
}

然后你可以这样使用:

public <T extends AbstractFoobar<T>> T fooGenerator(T foobar) {
  return foo(foobar, foobar::newInstance);
}
Bar foobar = foo(bar, Bar::new);

有效,因为您引用了特定类的构造函数。

而:

foo(foobar, T::new)

尝试引用泛型类型的构造函数。这根本不可能。记住关于类型擦除,在(非常(结束时,这里只有Object和演员表。 T::new根本不表示有意义的东西。

相关内容

最新更新