简体   繁体   English

我可以在 Java 中使用嵌套泛型(也称为更高种类的类型)吗?

[英]Can I use nested generics (aka higher kinded types) in Java?

I was trying to do something like:我试图做类似的事情:


public class MyClass <A, B, C <A, B> > {
  ...
}

But Eclipse highlights "B," and says "unexpected , expected extends".但是 Eclipse 突出显示“B”,并说“意外,预期扩展”。 What gives?是什么赋予了? Are nested generics not allowed?不允许嵌套泛型吗?

It's because you haven't defined C as a type that is itself typed with 2 type parameters.这是因为您尚未将C定义为本身使用 2 个类型参数键入的类型。
Try something like this:尝试这样的事情:

public class MyClass <A, B, C extends Map<A, B>> {
    // This compiles
}

If your template parameters don't share share a class hierarchy, you can use an interface.如果您的模板参数不共享共享类层次结构,则可以使用接口。

For example:例如:

interface IConverter<TFrom, TTo>
{
    TTo convert(TFrom from);
}

class IntToStringConverter implements IConverter<Integer, String>
{
    public String convert(Integer from)
    {
        return "This is a string: " + from.toString();
    }
}

class ConverterUser<TConverter extends IConverter<TFrom, TTo>, TFrom, TTo>
{
    public ConverterUser()
    {
    }

    private List<TConverter> _converter2;

    private TConverter _converter;

    public void replaceConverter(TConverter converter)
    {
        _converter = converter;
    }

    public TTo convert(TFrom from)
    {
        return _converter.convert(from);
    }
}

class Test
{
    public static void main(String[] args)
    {
        ConverterUser<IntToStringConverter, Integer, String> converterUser =
            new ConverterUser<IntToStringConverter, Integer, String>();

        converterUser.replaceConverter(new IntToStringConverter());

        System.out.println(converterUser.convert(328));
    }
}

This is not possible in Java.这在 Java 中是不可能的。 See the Type Variables section of the language definition along with Generic Classes and Type Parameters .请参阅语言定义的类型变量部分以及通用类和类型参数 I recently saw (somewhere) a mention that Java is incapable of this but Scala can do it.我最近看到(某处)提到 Java 无法做到这一点,但 Scala 可以做到。 This is confirmed by S4.4 of the Scala Language Specification . Scala Language Specification的 S4.4 证实了这一点。

This is also somewhat confirmed by the following code compiling successfully.下面的代码编译成功也一定程度上证实了这一点。

class MyClass [A, B, C [A, B]] {
}

Compiling in java yielded the follwing answers.在java中编译产生了以下答案。

MyClass.java:1: > expected
class MyClass <A, B, C<A, B>> {
                      ^
MyClass.java:1: <identifier> expected
class MyClass <A, B, C<A, B>> {
                        ^
MyClass.java:1: ';' expected
class MyClass <A, B, C<A, B>> {
                           ^
MyClass.java:2: reached end of file while parsing
}
 ^
4 errors

I would guess that there is an easier solution to your problem however, as this is somewhat unusual.但是,我猜想您的问题有一个更简单的解决方案,因为这有点不寻常。

You don't have to declare nested types like that.您不必像这样声明嵌套类型。 Simply简单地

class MyClass<A, B, C> {}

And when you create a MyClass, you could do something like当您创建 MyClass 时,您可以执行类似的操作

MyClass<List<String>, Set<Date>, Map<Integer, Long>> instance;

I am guessing you want MyClass to be a generic class with type parameters A, B, and C. Furthermore you want C to be a generic class with type parameters A and B.我猜您希望 MyClass 成为具有类型参数 A、B 和 C 的泛型类。此外,您希望 C 成为具有类型参数 A 和 B 的泛型类。

So that I could write这样我就可以写了

  1. MyClass < String , Date , Map < String , Date > >
  2. MyClass < String , Date , Hashtable < String , Date > > but not MyClass < String , Date , Hashtable < String , Date > >但不是
  3. MyClass < String , Date , ElementVsitor < Date , String > >

Then I don't think you can do that.那我觉得你做不到。

This is effectively asking for higher kinded types in Java.这实际上是在 Java 中要求更高种类的类型。 Java does not support this directly, but it can be simulated in a somewhat roundabout way like so Java 不直接支持这一点,但可以像这样以某种迂回的方式进行模拟

interface H<K, T> { }

Here H encodes a higher kinded type that takes a type parameter K which itself takes parameter T .这里H编码了一个更高种类的类型,它接受一个类型参数K ,它本身接受参数T

You can use this to eg implement a generic functor.您可以使用它来例如实现一个通用仿函数。 Note how fmap is effectively a function from H<K<T>> to H<K<R>> although we cannot directly declare it that way.请注意fmap是如何有效地从H<K<T>>H<K<R>>的函数,尽管我们不能直接以这种方式声明它。

public interface Functor<K> {
    <T, R> Function<H<K, T>, H<K, R>> lift(Function<T, R> f);

    default <T, R> H<K, R> fmap(Function<T, R> f, H<K, T> h) {
        return lift(f).apply(h);
    }
}

See also my Github repository for full working examples.另请参阅我的Github 存储库以获取完整的工作示例。 Further more have a look at this question , which takes the concept much further still.进一步看看这个问题,它使这个概念更进一步。

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

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