简体   繁体   English

Java 不允许用泛型调用递归方法?

[英]Java not allowed to call recursive method with generic type?

public class ResourceAssembler<T extends BasedEntity> {


    public Resource<T> toResource(T  entity) {
       ExtendsBasedEntity e = getExtendsBasedEntity();
       toResource(e); //<----compile error
       //some other code
    }
}

public class ExtendsBasedEntity extends BasedEntity{}

But if you call it from the outside its fine但是,如果您从外部调用它,那很好

//some other class
new ResourceAssembler<ExtendsBasedEntity>().toResource(new ExtendsBasedEntity())

Why?为什么?

Error:(28, 25) java: incompatible types: spring.BasedEntity cannot be converted to T

T may not be ExtendsBasedEntity , but some other subtype of BaseEntity , hence the compile error. T可能不是ExtendsBasedEntity ,而是BaseEntity的其他一些子类型,因此会出现编译错误。

One way to "fix" the problem, is to use a type token “解决”问题的一种方法是使用类型标记

public class ResourceAssembler<T extends BasedEntity> {

    private final Class<T> type;

    public ResourceAssembler(Class<T> type) {
        this.type = type;
    }

    public Resource<T> toResource(T  entity) {
       toResource(type.newInstance());
       //some other code
    }
}

Assuming that works for you.假设这对你有用。

Let's create two classes extending BasedEntity and call them EBE1 and EBE2 .让我们创建两个扩展BasedEntity的类并将它们命名为EBE1EBE2
Now you create a ResourceAssembly object using EBE1 as the type parameter.现在,您使用EBE1作为类型参数创建ResourceAssembly object。 But let's say that in the implementation of the toResource method you do something like return toResource(new EBE2());但是假设在toResource方法的实现中,您执行了类似return toResource(new EBE2()); . .

So the return type of toResource() is becoming Resource<EBE2> but that is wrong because according to the structure you should return Resource<EBE1> .所以toResource()的返回类型变成了Resource<EBE2>但这是错误的,因为根据结构你应该返回Resource<EBE1> And that's why the compile time error.这就是编译时错误的原因。 And type safety instincts of Java kicks in. Java 的类型安全本能开始发挥作用。

If you want to do return a generic for the toResource method then you either have to pass in the entity object down as it is or change it to the concrete type that you are initializing it within and not use generic (although I don't know why would anyone use the second option, but it's a "solution" to make it "compile").如果您想为toResource方法返回一个泛型,那么您要么必须按原样传递entity object,要么将其更改为您正在初始化它的具体类型而不使用泛型(尽管我不知道为什么有人会使用第二个选项,但它是使其“编译”的“解决方案”)。

Also, on the outside when you declare it.此外,在您声明它时在外面。 You are not specifying the type parameter for ResourceAssembly and hence it's a raw one.您没有为ResourceAssembly指定类型参数,因此它是原始参数。 Try to do it with a type param.尝试使用类型参数来完成。 You will have red squiggly lines there as well.你也会有红色的波浪线。

Here is an example:这是一个例子:

static class Resource<T> {

}

static class BasedEntity {

}

static class ExtendsBasedEntity1 extends BasedEntity {

}

static class ExtendsBasedEntity2 extends BasedEntity {

}
static public class ResourceAssembler<T extends BasedEntity> {


    public Resource<T> toResource(T entity) {
        return toResource(new ExtendsBasedEntity1()); //<----compile error
    }
}  



    public static void main(String[] args) {
        new ResourceAssembler<ExtendsBasedEntity1>().toResource(new ExtendsBasedEntity1()); // <---- No errors or warnings. This is valid and legal
        new ResourceAssembler<ExtendsBasedEntity2>().toResource(new ExtendsBasedEntity1()); // <----- red squiggly lines here
        new ResourceAssembler().toResource(new ExtendsBasedEntity2()); // <--compiler warning about raw types but no error
    }  

If you anyhow need to make it work the way you want it to, then instead of returning Resource<T> , return Resource<ExtendsBasedEntity> because you are recursing inside a generic method and looks like you need an object of concrete type to go in as the parameter for the recursive call.如果您无论如何需要使其按您希望的方式工作,那么不要返回Resource<T> ,而是返回Resource<ExtendsBasedEntity>因为您在泛型方法中递归并且看起来您需要一个具体类型的 object 到 go作为递归调用的参数。 So it would make sense to do so.所以这样做是有道理的。
Or else, go with @Bohemian's approach and make sure that in the class declaration of the type that you are using, there is a no-args constructor or else you will be having InstantiationException .或者,go 使用@Bohemian的方法,并确保在您使用的类型的 class 声明中,有一个无参数构造函数,否则您将拥有InstantiationException

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

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