英文:
Java equivalent of c#'s MakeGenericType to create instance of unknown generic type
问题
自从我接触过Java已经有很长时间了。但是根据以下的C#语法,是否可能在Java中创建一个未知的泛型类型的实例呢?
public void Send(Object message)
{
Class<?> requestType = message.getClass();
ReceiverWrapper<?> receiverInstance = (ReceiverWrapper<?>)
Class.forName("ReceiverWrapper").getDeclaredConstructor().newInstance();
// 对接收器进行一些操作...
}
所以想法是,Object message
是类型为 Message1
。我想创建一个 ReceiverWrapper<Message1>
的实例。
我不想在方法签名中使用泛型 - 就像 public <T> void Send(T message)
,因为我已经理解这点。我想知道是否可以从Object中提取类型信息,并根据该类型创建一个泛型。
英文:
Its been a long time since I have touched Java. But given the following C# syntax, is it possible to create an unknown instance of a generic type in java?
public void Send(object message)
{
Type requestType = message.GetType();
ReceiverWrapper receiverInstance = (ReceiverWrapper)
Activator.CreateInstance(typeof(ReceiverWrapper<>).MakeGenericType(requestType));
// do something with the receiver...
}
So the idea being Object message
is of type Message1
. I want to create an instance of ReceiverWrapper<Message1>
.
I don't want to use generics in method signature - ala public <T> void Send(T message)
as I already understand this in Java. I am curious whether we can extract type information from Object and create a generic based on that type.
答案1
得分: 3
Sure, here is the translated content:
> 我想要创建一个 ReceiverWrapper<Message1>
的实例。
在Java中没有这样的东西。只有 ReceiverWrapper
。Java中的泛型主要是在编译时使用的。例如,如果你有一个类型为 List<String>
的字段,你可以通过反射确定它 - 但是一个 对象 不是 ArrayList<String>
的实例,它只是 ArrayList
的实例。
英文:
> I want to create an instance of ReceiverWrapper<Message1>
.
There's no such thing in Java. There's just ReceiverWrapper
. Java generics are mostly a compile-time artifact. For example, if you have a field which is of type List<String>
you can determine that with reflection - but an object isn't an instance of ArrayList<String>
, it's just an instance of ArrayList
.
答案2
得分: 2
这里有一些需要解释的事情,首先 var 不是一种通用类型。Var 会在编译时被实际类型替换,所以如果你想使用泛型,你可能不应该使用 var。
public <T> void Send(T message)
{
ReceiverWrapper<T> receiverInstance = new ReceiverWrapper<>();
// 对接收器进行一些操作...
}
我不太确定你想要做什么,但类似这样的操作可能可以满足你的需求。
英文:
There are a few things to unpack here, first of all var is not a generic type. Var will be replaced by an actual type at compile time so if you want to use generics you probably shouldnt use var.
public <T> void Send(T message)
{
ReceiverWrapper<T> receiverInstance = new ReceiverWrapper<>();
// do something with the receiver...
}
I'm not entirely sure what you want to do with it but something like this?
答案3
得分: 1
„…在Java中是否有可能创建未知类型的泛型实例?…“
是的。是可能的。但只有在可以保证某些前提条件的情况下才能实现(请参阅代码中的注释)。
我在下面的代码片段中概述了这种技术的要点。可以在在线上运行实际实验…
{
...
Optional< Object > parameterizedType ...
TypeVariable< ? > typeVars[ ] ...
/* 前提条件1:目标必须是泛型类 */
if( typeVars.length == 0 ){ throw new NotAGenericTypeException( ); }
/* 前提条件2:目标必须公开一个构造函数,该构造函数声明为采用参数,
* 参数的类型与泛型类的类型参数部分中声明的类型相同 */
if( isConstructorCompatible ( target, typeVars ) ){
try{
parameterizedType = Optional.of( target.getClass( ).getConstructors( )[0].newInstance( typeArgs ) );
} catch( ReflectiveOperationException roe ){ roe.printStackTrace( ); }
}
return parameterizedType;
}
„…所以
Object message
的类型是Message1
。我想创建一个ReceiverWrapper<Message1>
的实例…“
尽管你的问题中的 Send(Object)
方法返回 void
,为了使我的概念验证更具测试性,我的实验性实现返回了参数化类型的实例…
...
public Optional< Object > send( Object message ){
return parameterizer.parameterize( ReceiverWrapper.class, message );
}
...
使用示例…
...
/* 设置@Andez使用案例的测试 */
Object sos = new Message( "太空之友,你们好吗?你们吃饭了吗?如果有时间,请来访问我们。" );
/* 正在测试的类 */
ProofOfConcept voyager = new ProofOfConcept( );
/* 执行测试的方法 */
Optional< Object > type voyager.send( sos );
/* 准备在之前的voyager.send( )调用中进行的参数化的结果 */
ReceiverWrapper< Message > oumuamua = type.map( raw -> (ReceiverWrapper< Message >)raw ).orElseThrow( AssertionError::new );
/* 利用编译器的类型检查 */
Message fromSpace = oumuamua.getMessage( );
/* 验证send( )返回的预期类型是类型参数的类型 */
assert ((Object)fromSpace) instanceof Message : "实验失败";
...
实验结果…
Message [ payload: 太空之友,你们好吗?你们吃饭了吗?如果有时间,请来访问我们。 ]
实验成功
他们曾说这是不可能的
英文:
> „…is it possible to create an unknown instance of a generic type in java?…“
Yes. It is possible. But only if certain preconditions can be guaranteed (see the comments in the code).
I outline the gist of the technique with the snippets below. The working experiment can be run online…
{
...
Optional< Object > parameterizedType ...
TypeVariable< ? > typeVars[ ] ...
/* Precondition #1: target MUST be a generic class */
if( typeVars.length == 0 ){ throw new NotAGenericTypeException( ); }
/* Precondition #2: target MUST expose a constructor that's declared to take arguments
* whose type is that of those declared in the generic class's type parameter section */
if( isConstructorCompatible ( target, typeVars ) ){
try{
parameterizedType = Optional.of( target.getClass( ).getConstructors( )[0].newInstance( typeArgs ) );
} catch( ReflectiveOperationException roe ){ roe.printStackTrace( ); }
}
return parameterizedType;
}
> „…So the idea being Object message
is of type Message1
. I want to create an instance of ReceiverWrapper<Message1>
…“
Although your question's Send(Object)
method returns void
, to make my proof of concept more testable my experimental implementation returns an instance of the parameterized type…
...
public Optional< Object > send( Object message ){
return parameterizer.parameterize( ReceiverWrapper.class, message );
}
...
Usage example…
...
/* Set up a test of @Andez's use case */
Object sos = new Message( "Friends of space, how are you all? Have you eaten yet? Come visit us if you have time." );
/* The class under test */
ProofOfConcept voyager = new ProofOfConcept( );
/* Exercise the method under test */
Optional< Object > type voyager.send( sos );
/* Prepare the outcome of the parameterization done in the previous voyager.send( ) call */
ReceiverWrapper< Message > oumuamua = type.map( raw -> (ReceiverWrapper< Message >)raw ).orElseThrow( AssertionError::new );
/* Leverage the compiler's type checking */
Message fromSpace = oumuamua.getMessage( );
/* Verify that the expected type returned by send( ) is the type of the type argument */
assert ((Object)fromSpace) instanceof Message : "EXPERIMENT FAILED";
...
Results of the experiment…
Message [ payload: Friends of space, how are you all? Have you eaten yet? Come visit us if you have time. ]
EXPERIMENT SUCCESSFUL
And they said it couldn't be done
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论