具有泛型类型作为成员变量的函数

huangapple go评论96阅读模式
英文:

Function with generic type as member variable

问题

我有一个将 class 对象映射到该类的实例的函数。
基本上:

  1. Function<Class<T>, T> fun;

我可以在方法内部定义这个函数,但是当尝试将其放在成员变量中时,编译器会报错,因为类型 T 是未知的。

因此,T 对于封闭对象不是特定的。它可能在每次调用时都不同。在类级别上定义这样一个函数的正确语法是什么?

编辑

我想澄清一下。我有一个类 A

  1. public class A {
  2. public <T> T get(Class<T> clazz) {...}
  3. }

现在,我想将指向该函数的指针传递给类 B,就像这样:

  1. public class B {
  2. <T> Function<Class<T>, T> fun;
  3. public <T> T get(Class<T> clazz) {
  4. return fun.apply(clazz);
  5. }
  6. }

然而,<T> Function<Class<T>, T> fun 的语法是不正确的。有没有办法保持 fun 将始终保留类型 T 的信息?

我目前的解决方案是

  1. public class B {
  2. Function<Class<?>, ?> fun;
  3. public <T> void setFun(Function<Class<T>, T> fun) {
  4. this.fun = fun;
  5. }
  6. public <T> T get(Class<T> clazz) {
  7. return (T) fun.apply(clazz);
  8. }
  9. }

这可以工作(并且显然通过不变式是正确的),但由于需要强制转换,有点丑陋。

英文:

I have a function which maps a class object to an instance of this class.
Basically:

  1. Function&lt;Class&lt;T&gt;, T&gt; fun;

I can define this function within a method but when trying to put this in a member variable, the compiler complains because the type T is unknown.

So, T is not specific to the enclosing object. It might differ from call to call. What is the correct syntax to define such a function on class level?

EDIT

I would like to clarify. I have class A

  1. public class A {
  2. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {...}
  3. }

Now, I want to hand a pointer to that function to class B like this:

  1. public class B {
  2. &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun;
  3. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
  4. return fun.apply(clazz);
  5. }
  6. }

However, the Syntax for &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun is incorrect. Is there a way to keep the information, that fun will always retain the type T?

My current solution is

  1. public class B {
  2. Function&lt;Class&lt;?&gt;, ?&gt; fun;
  3. public &lt;T&gt; void setFun(Function&lt;Class&lt;T&gt;, T&gt; fun) {
  4. this.fun = fun;
  5. }
  6. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
  7. return (T) fun.apply(clazz);
  8. }
  9. }

This works (and is obviously correct via invariant) but kinda ugly because of the required cast.

答案1

得分: 3

在Java(以及JVM)中,值不具有多态性,方法具有多态性。

因此,正确的方法是用一个方法来定义它:

  1. <T> Function<Class<T>, T> fun();

关于编辑部分。

现在,我想将一个指向该函数的指针传递给类B,如下所示:

  1. public class B {
  2. <T> Function<Class<T>, T> fun;
  3. public <T> T get(Class<T> clazz) {
  4. return fun.apply(clazz);
  5. }
  6. }

再次强调,值(包括字段)不能具有多态性,方法可以。

  • 因此,你可以将fun设置为一个方法:
  1. public abstract class B {
  2. abstract <T> Function<Class<T>, T> fun();
  3. public <T> T get(Class<T> clazz) {
  4. return this.<T>fun().apply(clazz);
  5. }
  6. }

你不能像setFun这样编写setter。其签名应该是类似以下形式:

  1. public void setFun(Function<Class<T>, T> fun); // 伪代码

而不是:

  1. public <T> void setFun(Function<Class<T>, T> fun);

<T> Function<Class<T>, T> 被称为rank-N类型,在Java中不存在。

或者,你可以用一个类(接口)来封装多态的fun

  1. public interface PolyFunction {
  2. <T> T apply(Class<T> clazz);
  3. }
  4. public class B {
  5. PolyFunction fun;
  6. public void setFun(PolyFunction fun) {
  7. this.fun = fun;
  8. }
  9. public <T> T get(Class<T> clazz) {
  10. return fun.apply(clazz);
  11. }
  12. }

PolyFunction 类似于你的A,所以也许你想要:

  1. public class B {
  2. A a;
  3. public void setA(A a) {
  4. this.a = a;
  5. }
  6. public <T> T get(Class<T> clazz) {
  7. return a.get(clazz);
  8. }
  9. }
英文:

In Java (and JVM) values are not polymorphic, methods are.

So correct is to define it with a method

  1. &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun();

https://stackoverflow.com/questions/34886128/polymorphic-values-in-java


Regarding EDIT.

> Now, I want to hand a pointer to that function to class B like this:
>
> public class B {
> <T> Function<Class<T>, T> fun;
>
> public <T> T get(Class<T> clazz) {
> return fun.apply(clazz);
> }
> }

Once again, a value (including a field) can't be polymorphic, method can.

  • So you can make fun a method

    1. public abstract class B {
    2. abstract &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun();
    3. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
    4. return this.&lt;T&gt;fun().apply(clazz);
    5. }
    6. }

    You can't write setter like setFun. Its signature should be something like

    1. public void setFun(&lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun); // pseudocode

    rather than

    1. public &lt;T&gt; void setFun(Function&lt;Class&lt;T&gt;, T&gt; fun);

    &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; is called rank-N type and it's absent in Java

    https://stackoverflow.com/questions/12031878/what-is-the-purpose-of-rank2types

    https://wiki.haskell.org/Rank-N_types

  • Alternatively, you can wrap polymorphic fun with a class (interface)

    1. public interface PolyFunction {
    2. &lt;T&gt; T apply(Class&lt;T&gt; clazz);
    3. }
    4. public class B {
    5. PolyFunction fun;
    6. public void setFun(PolyFunction fun) {
    7. this.fun = fun;
    8. }
    9. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
    10. return fun.apply(clazz);
    11. }
    12. }

    PolyFunction looks like your A so maybe you want

    1. public class B {
    2. A a;
    3. public void setA(A a) {
    4. this.a = a;
    5. }
    6. public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
    7. return a.get(clazz);
    8. }
    9. }

huangapple
  • 本文由 发表于 2020年9月15日 21:14:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/63902642.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定