java - 访问参数化类型的参数化类型

标签 java generics

小问题

有没有可能在 Java 中做这样的事情:

public interface Processor<T extends Producer> {
    <T2> T2 process(T<T2> producer);
}

生产者声明为 Producer<T>

长问题

如果 Java 中的类型 A 用类型 B 参数化,类型 B 也是通用的,是否可以以某种方式在 A 中使用 B 的参数化类型?我知道,这很神秘。

假设我们有一个通用的 Producer 接口(interface):

public interface Producer<T> {
    T produce();
}

这个接口(interface)的实现也是通用的。它们在生成对象的类型上没有区别,而是在生成对象的方式上有所不同,因此可能有:DatabaseProducer、RandomProducer 等。

我们还有一个处理器接口(interface)。处理器的特定实现可以与生产者的特定实现协同工作,但处理器也不关心处理对象的类型。我们可以很容易地实现这种情况:

public class MyProducer<T> implements Producer<T> {
    @Override
    public T produce() {
        (...)
    }
}

public class MyProcessor implements Processor<MyProducer> {
    <T> T process(MyProducer<T> producer) {
        return producer.produce();
    }
}

MyProcessor 的 process() 方法获取通用的 MyProducer 并只返回它生成的内容。此实现将与 String、Integer 或其他对象的生产者一起使用,只要生产者是 MyProducer 类型即可。

现在的问题是如何编写通用处理器接口(interface)。此接口(interface)使用生产者类型进行参数化,该方法应返回相关生产者的参数化类型。

我们不能这样做:

public interface Processor<T extends Producer> {
    <T2> T2 process(T<T2> producer);
}

或类似的东西:

public interface Processor<T extends Producer> {
    T.T process(T producer);
}

甚至可以用 Java 实现吗?有什么理由不能或不应该支持它,或者这只是一个缺失的功能?我认为编译器可以完全理解这种情况并检查类型是否正确。


更新

具有两个参数化类型的解决方案,例如:

public interface Processor<T extends Producer<T2>, T2> {
    T2 process(T producer);
}

不是我要找的。请注意,MyProcessor 未绑定(bind)到任何特定类型的生成对象。从 process() 方法返回的类型是在调用站点推断的。

我还了解类型删除的工作原理以及与之相关的问题。问题是:由于类型删除,这种情况是有问题的还是不可能的?我相信不会。

如果我们有一个常规的泛型方法,例如:

<T> T process(MyProducer<T> producer) {
    return producer.produce();
}

我们称之为:

MyProducer<String> prod = (...);
String result = processor.process(prod);

那么一切都会好起来的。当然,在这种情况下,String 会被删除,process() 和 produce() 方法都会在生成的字节码中返回 Object,但编译器会理解 MyProducer.produce() 实际上会返回 String,因此 process() 也会返回 String。我不明白为什么在我的情况下它不能以同样的方式工作:

public interface Processor<T extends Producer> {
    <T2> T2 process(T<T2> producer);
}

编译器从传递的生产者对象推断出调用点的返回类型,并且它可以按照与上述相同的方式证明实现是正确的。我认为现在 Java 中唯一缺少的是编译器应该注意到 T 扩展了泛型类型,所以 T<T2>可以被视为类似于 Producer<T2> .也许我在这里没有看到重要的东西。

最佳答案

您可以在类级别或方法级别使用泛型。如果您需要让 Processor 使用特定类型的 Producer,那么您可以这样定义 Processor:

public interface Producer<T> {
    T produce();
}

public interface Processor< T, P extends Producer<T> > {
    public T process(P producer);
}

public class MyProducer<T> implements Producer<T> {
    @Override
    public T produce() {
        return null;
    }
}

public class MyProcessor<T> implements Processor<T, MyProducer<T> > {

    public T process(MyProducer<T> producer) {
        return producer.produce();
    }
}

更新 1:

我不明白使 Processor 接口(interface)通用然后在其中使用原始类型的 Producer 有什么意义。如果您不想将 Processor 参数化为任何类型的 Producer,那么您可以在方法级别声明参数化类型:

    public static interface Processor {
        public <T> T process(Producer<T> producer);
    } 

    public static class MyProcessor implements Processor{

        public <T> T process(Producer<T> producer) {
            return producer.produce();
        }
    }

    //in here we wont have any compilation errors
    String result = new MyProcessor().process( new MyProducer<String>() );

顺便说一句,我不喜欢你如何声明 MyProducer 是通用的,而不是展示你将如何知道在 produce() 方法中返回什么类型的对象。

更新 2:

在这种情况下,我认为我们不能不进行转换。这是另一个没有限制 Producer 的版本,需要强制转换:

public static interface Processor< P extends Producer<?> > {
    public <T> T process(P producer);
}

public static class MyProcessor implements Processor< MyProducer<?> > {

    @SuppressWarnings("unchecked")
    public <T> T process(MyProducer<?> producer) {
        return (T)producer.produce();
    }
}

//again this will work without any compilation errors
String result = new MyProcessor().process( new MyProducer<String>() 

关于java - 访问参数化类型的参数化类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44552019/

相关文章:

java - Spring boot(2.0.3.RELEASE)应用程序中的内存泄漏

java - Hibernate 更新子集合

java - java中new的返回值

java - 为什么gradle使用2个本地缓存?

Java - 如何对通用 ArrayList 进行子类化,以便 MyArrayList<foo> 的实例成为 ArrayList<foo> 的子类?

java - 泛型通配符不接受实现接口(interface)的类

java - 我尝试过 stackoverflow 上的所有答案,但失败了

用于类似动态类型转换的 Java 反射/通用类型

Java 泛型——需要解释

c++ - 创建一个方法来使用模板迭代自定义类的任何容器?