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

时间:2017-06-14 18:22:57

标签: java generics

简短的问题

无论如何都可以在Java中做这样的事情:

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

其中Producer被声明为Producer<T>

长问题

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

假设我们有一个通用的Producer界面:

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

此接口的实现也是通用的。它们在生产对象的类型上没有区别,而在于它们如何生成它们,因此可能有:DatabaseProducer,RandomProducer等。

我们还有一个处理器接口。处理器的特定实现能够与生成器的特定实现一起工作,但处理器也不关心处理对象的类型。我们可以很容易地实现这样的案例:

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,只返回它生成的内容。只要生产者属于MyProducer类型,此实现将与String,Integer或其他对象的生成者一起使用。

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

我们做不到这样的事情:

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未绑定到任何特定类型的生成对象。从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>。也许我在这里看不到重要的东西。

2 个答案:

答案 0 :(得分:1)

您可以在类级别或方法级别使用泛型。如果您需要让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接口设为通用,然后在其中使用带有原始类型的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>() 

答案 1 :(得分:0)

这是不可能的,因为您的通用类型是 Non-Reifiable

  

不可兑换类型

     

可再生类型是类型信息完全可用的类型   在运行时。这包括原语,非泛型类型,原始类型,   和未绑定的通配符的调用。

     

不可再生类型是已删除信息的类型   按类型擦除编译时 - 对泛型类型的调用   未定义为无界通配符。不可重复的类型没有   它在运行时可用的所有信息。不可再生的例子   类型是List和List; JVM说不清楚   运行时这些类型之间的差异。如限制所示   泛型,在某些情况下,非可再生类型   不能使用:例如,在表达式的实例中,或作为   数组中的元素。

可以通过在界面中使用其他类型来完成非常简单的解决方法:

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

回答问题更新:

我想说在这种情况下是不可能的,因为ProducerT没有实际关系。可能的是在Producer接口中创建内部类并将其用作类型:

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

    class NotGenericType <T>{
        // inner T != outter T 
        // do something with T ?
    }
}

public interface Processor<P extends Producer>{
    // NotGenericType belongs to the type P
    P.NotGenericType process(P producer);

    // Won't work because there is no relation between T and Producer
    // P.T process(P producer);
}
但是,我没想到这会有什么用处。