简体   繁体   English

如何通过泛型方法引用作为参数?

[英]How to pass generic method reference as parameter?

I would like to pass generic method reference as a parameter in java method. 我想将通用方法引用作为参数传递给java方法。

Just for an example I have prepared some abstract 仅作为示例,我准备了一些摘要

public abstract class AbstractFoobar{

    abstract String getLiteral();
}

and 2 classes that its extend. 和2个扩展的类。 Classes have String parameter constructor. 类具有String参数构造函数。

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

I have a simple generic method that creates new instance of the Objects. 我有一个简单的通用方法,可以创建对象的新实例。 The creation bases on Function creator parameter 创建基于函数创建者参数

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

This example works perfectly when the method foo is executed with specific method reference Bar::new. 当使用特定的方法引用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());
}

But I dont know how to pass the reference method through the wrapper method fooGenerator 但是我不知道如何通过包装方法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 Compiler cannot instantiate the type T #1编译器无法实例化类型T

#2 the method foo(..., Function<>) is not applicable for the argument Constructor<> #2方法foo(...,Function <>)不适用于参数Constructor <>

A very important, but never emphasized enough, point about Java generics is that they are just a fancy way to avoid writing explicit casts . 关于Java泛型的一个非常重要但从未强调过的要点是, 它们只是避免编写显式强制转换的一种理想方式 They are nothing more, nothing less. 他们仅此而已。

So, if you can't write: 所以,如果你不能写:

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

// Call site
Bar foobar = (Bar) foo(bar);

then you can't do it with generics. 那么您将无法使用泛型。 And there isn't such a thing, because constructors do not participate in inheritance: AbstractFoobar::new would create an instance of AbstractFoobar (if it could be instantiated), not a subclass. 而且没有这样的事情,因为构造函数不参与继承: AbstractFoobar::new将创建AbstractFoobar的实例(如果可以实例化),而不是子类。

For you current AbstractFoobar definition, you can't do anything better than just invoking foo directly, with the explicit arguments. 对于您当前的AbstractFoobar定义,除了直接使用显式参数直接调用foo ,您无法做其他任何事情。


The only way you could do it with a single parameter is if the AbstractFoobar had a factory method on it, eg 您可以使用单个参数执行此操作的唯一方法是,如果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); }
}

which you could then use like: 然后可以像这样使用:

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

is valid because you reference the constructor for a specific class. 是有效的,因为您引用了特定类的构造函数。

Whereas: 鉴于:

foo(foobar, T::new)

tries to reference the constructor of a generic type. 尝试引用泛型类型的构造函数。 And that is simply not possible. 那根本不可能。 Remember about type erasure, in the (very) end, there are just Object s here, and casts. 记住类型擦除,在(非常)端,这里只有Object ,并且强制转换。 T::new simply does not denote something meaningful. T::new根本不表示有意义的事情。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM