Convert Generic Types to Objects

huangapple go评论78阅读模式
英文:

Convert Generic Types to Objects

问题

我正在编写一个转换器,将String输入转换为自定义类型的输出。以下是interface的外观:

public interface Transformer<T> {
    public T transform(String input);
}

将会有多个实现(例如IntegerTransformerByteTransformer等)。我编写了一个工厂来返回这些转换器,例如:

public class TransformerFactory {
    public <T> Transformer<T> getTransformer(final SomeEnum enum, final T type) {
        switch(enum) {
        case FOO:
            return new IntegerTransformer();
        case BAR:
            return new ByteTransformer();
        default:
            throw new Exception("blah");
        }
    }
}

在我的main类中,我正在做以下操作:

factory.getTransformer(foo, Integer.class).transform(input);

这会导致以下错误:

Type mismatch: cannot convert from Class<Integer> to Integer

因此,我需要以某种方式将Type文字转换为Object,是否有任何方法可以在不修改接口和工厂的泛型结构的情况下实现这一点呢?

英文:

I am writing a transformer to convert String input to output of custom type. Here's how the interface looks like:

public interface Transformer&lt;T&gt; {
	public T transform(String input);
}

There will multiple implementations of it (i.e. IntegerTransformer, ByteTransformer etc). I have written a factory that returns these transformers, e.g.:

public class TransformerFactory {
    public &lt;T&gt; Transformer&lt;T&gt; getTransformer(final SomeEnum enum, final T type) {
		switch(enum) {
		case FOO:
			return new IntegerTransformer();
		case BAR:
			return new ByteTransformer();
			default:
				throw new Exception(&quot;blah&quot;);
		}
	}
}

In my main class, I am doing this:

factory.getTransformer(foo, Integer.class).transform(input);

This results in the following error:

Type mismatch: cannot convert from Class&lt;Integer&gt; to Integer

So, I somehow need to convert Type literal to Object. Is there any way I can do that without modifying the generic structure of interface and factory?

答案1

得分: 1

getTransformer(final SomeEnum enum, final T type)的签名期望一个真正的类型为T的对象。你想要的是传递一个class的实例,所以应该是:
getTransformer(final SomeEnum enum, final Class&lt;T&gt; type)

另外,自从Java 8以来,不再需要声明这种简单的接口。使用泛型的Function&lt;String,T&gt;会非常适合你。

英文:

The signature of getTransformer(final SomeEnum enum, final T type) expects an actual objet of type T. What you want is pass a instance of class, so it should be:
getTransformer(final SomeEnum enum, final Class&lt;T&gt; type)

In addition, since Java 8 there is no need for declaring such simple interfaces. Using the generic Function&lt;String,T&gt; would serve you perfectly.

答案2

得分: 1

TL;DR: 并不是试图抢夺 @MAnouti 标记给他/她的分数。但为了完整起见,楼主,我想分享一下我在尝试重现你的错误时观察到的内容。

> "这导致了以下错误:"
>
> 类型不匹配:无法从 Class<Integer> 转换为 Integer

你问题中的原始示例代码无法编译通过(正如我尝试重现相同错误所证实的那样),出现了这些不同的编译错误...

...
不兼容的类型:无法将 IntegerTransformer 转换为 Transformer&lt;T&gt;
...
不兼容的类型:无法将 ByteTransformer 转换为 Transformer&lt;T&gt;
...

...注意这些与你在问题中报告的错误不同。

而且,即使你按照其他答案/评论的建议,将方法的第二个形式参数从 T 替换为 Class&lt;T&gt;,你仍然会得到上述的 不能转换为 Transformer&lt;T&gt; 编译错误。

> "…是否有任何方法可以在不修改接口和工厂的泛型结构的情况下实现?"

我通过一个简单的实验进行了确认,证明了这符合这个条件。而且它成功地编译并按预期运行...

    public &lt; T, U extends Transformer&lt; T &gt; &gt; U getTransformer( SomeEnum eNum, Class&lt; T &gt; type ){ 
    
    switch( eNum ){ 
        case FOO:
            return (U)new IntegerTransformer( );
        case BAR:
            return (U)new ByteTransformer( );
        default:
            throw new RuntimeException( &quot;Detected Decepticons Among Us!&quot; );
    }
}

...它修复了你在问题中报告的错误,同时也修复了如果你只改变了参数为 Class&lt;T&gt; 的情况下会出现的*不能转换为 Transformer&lt;T&gt;*错误。

英文:

TL;DR: Not trying to snipe @MAnouti's points that you've earmarked for him/her. But for the sake of completeness, OP, I wanted to share what I observed in my attempt to reproduce your error.


> „This results in the following error:
>
> Type mismatch: cannot convert from Class<Integer> to Integer

The original example code in your question fails to compile (as confirmed by my failed attempt to reproduce the same error) with these different compilation errors&hellip;

...
incompatible types: IntegerTransformer cannot be converted to Transformer&lt;T&gt;
...
incompatible types: ByteTransformer cannot be converted to Transformer&lt;T&gt;
...

&hellip;Notice those are not the same as the error you reported in your question.

And even if you did follow the advice of the other answers/comments and replaced T with Class&lt;T&gt; as the second formal parameter of your method, you would still get the above cannot be converted to Transformer&lt;T&gt; compilation errors.

> „&hellip;Is there any way I can do that without modifying the generic structure of interface and factory?

I have confirmed by a simple experiment that this meets that criteria. And it successfully compiles and runs as expected&hellip;

    public &lt; T, U extends Transformer&lt; T &gt; &gt; U getTransformer( SomeEnum eNum, Class&lt; T &gt; type ){ 
    
    switch( eNum ){ 
        case FOO:
            return (U)new IntegerTransformer( );
        case BAR:
            return (U)new ByteTransformer( );
        default:
            throw new RuntimeException( &quot;Detected Decepticons Among Us!&quot; );
    }
}

&hellip;It fixes both the error you reported in your question, and the cannot be converted to Transformer&lt;T&gt; errors you'd get if the only thing you changed was the parameter to Class&lt;T&gt;.

huangapple
  • 本文由 发表于 2020年8月14日 18:46:45
  • 转载请务必保留本文链接:https://go.coder-hub.com/63411281.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定