简体   繁体   English

使用未知的泛型类型实例化并应用泛型方法-Java

[英]Instantiate and apply generic method with unknown generic type - Java

I need to instantiate an object with an unknown generic type and then apply a generic method to it. 我需要实例化具有未知通用类型的对象,然后对其应用通用方法。 Here is where I stand : 我站在这里:

public static void main(String[] args)
{
    BarIf bar = newRandomBarImpl();

    Foo foo1 = newFooBar(bar.getClass()); // warning
    Foo<?> foo2 = newFooBar(bar.getClass()); // error
    Foo<? extends BarIf> foo3 = newFooBar(bar.getClass()); // error

    foo1.doSomething(bar); // warning
    foo2.doSomething(bar); // error
    foo3.doSomething(bar); // error
}

static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}

static <T extends BarIf> T newRandomBarImpl(){}

interface FooIf<T extends BarIf>
{
    public void doSomething(T t);
}

interface BarIf{}

class Foo<T extends BarIf> implements FooIf<T>
{
    public void doSomething(T t){}
}

The strange thing is that for foo2 and foo3, the newFooBar() method returns FooIf rather than Foo. 奇怪的是,对于foo2和foo3,newFooBar()方法返回FooIf而不是Foo。 I guess the type inference is messy. 我猜类型推断是一团糟。 But I can't pass the method generic parameters since I don't know the Bar type. 但是由于我不知道Bar类型,所以无法传递方法的通用参数。

What I would need is Foo<bar.getClass()> . 我需要的是Foo<bar.getClass()> Is there a way to do it? 有办法吗?

I tried using TypeToken but I end up with a T type rather than the actual Bar type. 我尝试使用TypeToken,但最终得到的是T类型而不是实际的Bar类型。 Any chance using that? 有机会使用吗?

First of all, a declaration like 首先,像

static <T extends BarIf> T newRandomBarImpl(){}

is nonsense. 废话 It basically says “whatever the caller substitutes for T , the method will return it”. 它基本上说:“无论调用者用什么替换T ,该方法都将返回它”。 In other words, you can write 换句话说,你可以写

ArbitraryTypeExtendingBarIf x=newRandomBarImpl();

without getting a compiler warning. 没有得到编译器警告。 Obviously, that can't work. 显然,这是行不通的。 newRandomBarImpl() doesn't know anything about ArbitraryTypeExtendingBarIf . newRandomBarImpl()ArbitraryTypeExtendingBarIf一无所知。 The method name suggests that you actually want to express that newRandomBarImpl() can return an arbitrary implementation of BarIf , but that's an unnecessary use of Generics, 方法名称建议您实际上要表达newRandomBarImpl()可以返回BarIf的任意实现,但这是对BarIf的不必要使用,

BarIf newRandomBarImpl(){}

already expresses that this method can return an arbitrary subtype of BarIf . 已经表示此方法可以返回BarIf的任意子类型。 In fact, since BarIf is an abstract type, this method must return a subtype of BarIf and it's nowhere specified which one it will be. 实际上,由于BarIf是抽象类型,因此此方法必须返回BarIf的子类型,并且在任何地方都没有指定它将是哪种类型。

The same applies to the declaration 声明同样如此

static <T extends FooIf<S>, S extends BarIf> T newFooBar(Class<S> barClass){}

It also claims that the caller can choose which implementation of FooIf the method will return. 它还声称,调用者可以选择FooIf方法将返回的实现。 The correct declaration would be 正确的声明是

static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}

as the method decides which implementation of FooIf it will return, not the caller. 该方法决定返回的FooIf实现,而不是调用方。


Regarding your other attempts to deal with FooIf , you can't work this way using a type parametrized with a wildcard, nor can you fix it using Reflection. 关于您处理FooIf的其他尝试,您不能使用带通配符参数化的类型来以这种方式工作,也不能使用Reflection对其进行修复。 But you can write generic code using a type parameter: 但是您可以使用类型参数编写通用代码:

public static void main(String[] args)
{
    BarIf bar = newRandomBarImpl();
    performTheAction(bar.getClass(), bar);
}
static <T extends BarIf> void performTheAction(Class<T> cl, BarIf obj) {
    FooIf<T> foo=newFooBar(cl);
    foo.doSomething(cl.cast(obj));
}
static <S extends BarIf> FooIf<S> newFooBar(Class<S> barClass){}
static BarIf newRandomBarImpl(){}

interface FooIf<T extends BarIf> {
    public void doSomething(T t);
}
interface BarIf{}

The method performTheAction is generic, in other words, works with an unknown type expressed as type parameter T . performTheAction方法是通用的,换句话说,它适用于表示为类型参数T的未知类型。 This method can be invoked with an unknown type ? extends BarIf 可以使用未知类型调用此方法? extends BarIf ? extends BarIf as demonstrated in the main method. main方法中所示? extends BarIf

However, keep in mind, that every reference to a type X implies that the referred object might have a subtype of X without the need to worry about it. 但是,请记住,每个对类型X引用都意味着所引用的对象可能具有X的子类型,而不必担心它。

You can simply use the base class BarIf here, regardless of which actual subtype of BarIf the object has: 您可以在此处简单地使用基类BarIf ,而不管对象的实际BarIf子类型为:

BarIf bar = newRandomBarImpl();
FooIf<BarIf> foo=newFooBar(BarIf.class);
foo.doSomething(bar);

Note that when you want to use methods of the actual implementation type Foo , not specified in the interface, you will have to cast the FooIf to Foo . 请注意,当您要使用接口中未指定的实际实现类型Foo方法时,必须将FooIfFoo You can cast a FooIf<BarIf> to Foo<BarIf> without a warning as the generic type conversion is correct if Foo<X> implements FooIf<X> . 您可以将FooIf<BarIf>Foo<BarIf>而不发出警告,因为如果Foo<X> implements FooIf<X> ,则泛型类型转换是正确的。

However, it can fail at runtime as the method newFooBar is not required to return an instance of Foo rather than any other implementation of FooIf . 但是,它可能会在运行时失败,因为不需要newFooBar方法来返回Foo实例而不是其他任何FooIf实现。 That's why an explicit type cast is the only correct solution as it documents that there is an assumption made about the actual runtime type of an object. 这就是为什么显式类型转换是唯一正确的解决方案的原因,因为它记录了有关对象的实际运行时类型的假设。 All other attempts will generate at least one compiler warning somewhere. 所有其他尝试将在某处生成至少一个编译器警告。

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

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