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

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

Function with generic type as member variable

问题

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

 Function<Class<T>, T> fun;

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

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

编辑

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

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

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

public class B {
  <T> Function<Class<T>, T> fun;

  public <T> T get(Class<T> clazz) {
    return fun.apply(clazz);
  }
}

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

我目前的解决方案是

public class B {
  Function<Class<?>, ?> fun;

  public <T> void setFun(Function<Class<T>, T> fun) {
    this.fun = fun;
  }

  public <T> T get(Class<T> clazz) {
    return (T) fun.apply(clazz);
  }
}

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

英文:

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

 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

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

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

public class B {
  &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun;
  
  public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
    return fun.apply(clazz);
  }
}

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

public class B {
  Function&lt;Class&lt;?&gt;, ?&gt; fun;

  public &lt;T&gt; void setFun(Function&lt;Class&lt;T&gt;, T&gt; fun) {
    this.fun = fun;
  }

  public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
    return (T) fun.apply(clazz);
  }
}

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

答案1

得分: 3

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

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

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

关于编辑部分。

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

public class B {
  <T> Function<Class<T>, T> fun;
 
  public <T> T get(Class<T> clazz) {
    return fun.apply(clazz);
  }
}

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

  • 因此,你可以将fun设置为一个方法:
public abstract class B {
   abstract <T> Function<Class<T>, T> fun();

   public <T> T get(Class<T> clazz) {
       return this.<T>fun().apply(clazz);
   }
}

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

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

而不是:

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

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

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

public interface PolyFunction {
    <T> T apply(Class<T> clazz);
}

public class B {
    PolyFunction fun;

    public void setFun(PolyFunction fun) {
        this.fun = fun;
    }

    public <T> T get(Class<T> clazz) {
        return fun.apply(clazz);
    }
}

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

public class B {
    A a;

    public void setA(A a) {
        this.a = a;
    }

    public <T> T get(Class<T> clazz) {
        return a.get(clazz);
    }
}
英文:

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

So correct is to define it with a method

&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

     public abstract class B {
        abstract &lt;T&gt; Function&lt;Class&lt;T&gt;, T&gt; fun();
    
        public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
            return this.&lt;T&gt;fun().apply(clazz);
        }
     }
    

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

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

    rather than

     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)

    public interface PolyFunction {
        &lt;T&gt; T apply(Class&lt;T&gt; clazz);
    }
    
    public class B {
        PolyFunction fun;
    
        public void setFun(PolyFunction fun) {
            this.fun = fun;
        }
    
        public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
            return fun.apply(clazz);
        }
    }
    

    PolyFunction looks like your A so maybe you want

    public class B {
        A a;
    
        public void setA(A a) {
            this.a = a;
        }
    
        public &lt;T&gt; T get(Class&lt;T&gt; clazz) {
            return a.get(clazz);
        }
    }
    

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:

确定