InvokeExact对象,其类型由classloader动态加载 [英] InvokeExact on the object, whose type is dynamically loaded by classloader

查看:284
本文介绍了InvokeExact对象,其类型由classloader动态加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经花了一整天的时间来解决这个问题。我的问题是如何对一个实例进行MethodHandle.invokeExact调用,其类类型是在程序运行时动态加载。为了使问题更清楚,我显示我的示例代码如下:

I have spend whole day on this problem. My problem is how to make an MethodHandle.invokeExact invocation on an instance, whose class type is dynamically loaded at program runtime. To make problem more clear, i show my sample code below:

Class<?> expClass = new MyClassLoader().load(....)

//expClass is AddSample.class which is subclass of BaseTemplate         
 BaseTemplate obj = expClass.getConstructor(...)
                .newInstance(...);
MethodHandle myMH = MethodHandles.lookup().findVirtual(expClass, methodName,..);
System.out.println("Object type "+obj.getClass()); //Print AddSample

// If obj is declared as "AddSample obj", the runtime would be OK.
assertEquals((int)myMH.invokeExact(obj,"addintaasdsa" , 10 , 20.0f), 12);

在此示例中,expClass是动态加载的,其类类型为 AddSample 。下一行中的obj实例声明为BaseTemplate,其实际类型为 AddSample 。类AddSample是BaseTemplate的子类。然后,一个MethodHandle myMh被创建到 AddSample 的添加函数,但myMH的调用失败,因为receiverType不匹配。

In this sample, expClass is dynamically loaded and its class type is AddSample. The obj instance in the next line is declared to be BaseTemplate, and its real type is AddSample. Class AddSample is subclass of BaseTemplate. Then a MethodHandle myMh is created to the add function of AddSample but the invocation of myMH fails because of receiverType does not match.

myMH.invokeExact 引发运行时错误

java.lang.invoke.WrongMethodTypeException: expected (AddSample,String,int,float)int but found (Object,String,int,float)int

,因为 myMH 的接收者被声明为在expClass(AddSample)接收器 obj 当前提供的是声明的BaseTemaplte,尽管obj的类是AddSample。 InvokeExact需要精确的参数匹配。

because the receiver of this myMH is declared to be on expClass (AddSample), but the receiver obj current provided is declared BaseTemaplte, though the obj's Class is AddSample. InvokeExact requires exact parameter match.

我的问题可能简化为:
如何将实例从其基本类型强制转换为子类型是动态加载?

My problem might be simplified as: how to cast an instance from its base type to a child type which is dynamically loaded?

BaseTemplate obj = ...
Class<?> newType = Class('AddSample') //dynamic loaded...



将obj的声明类型更改为AddSample ?



UPDATE:

Class<T> expClass = (Class<T>) new MyClassLoader().run(className, methodName, b);
BaseTemplate obj = ..
Class<T> newType = (Class<T>) obj.getClass().getClassLoader().loadClass("AddSample");
T tObj = newType.cast(obj);
assertEquals((int)myMH.invokeExact(tObj,"addintaasdsa" , 10 , 20.0f), 12);

使用强制转换无法解决与先前结果相同的问题。原因仍然是给定的参数不完全匹配myMH声明。更清楚的是当我检查生成的字节码:

Using cast does not help fix the problem which is the same previous result. The reason is still that the given parameter does not exact match myMH declaration. It would be more clear when i check the generated bytecodes:

L23  # For cast 
    LINENUMBER 126 L23
    ALOAD 10: newType
    ALOAD 8: obj
    INVOKEVIRTUAL Class.cast (Object) : Object  #tObj is Object and its real type is AddSample here
    ASTORE 11
   L24
    LINENUMBER 128 L24
    ALOAD 9: myMH           # Push myMH to stack
    ALOAD 11: tObj          # Push tObj to Stack. tObj is declared Object type and its real type is AddSample. 
    LDC "addintaasdsa"      #Push String to Stack
    BIPUSH 10               #Push int to Stacl
    LDC 20.0                #Push float to Stack 
    INVOKEVIRTUAL MethodHandle.invokeExact (Object, String, int, float) : int

myMH指向
(AddSample, String,int,float)int ,但是给定参数:
(Object,String,int,float)
这导致运行时错误,我以前显示。

the myMH points to (AddSample,String,int,float)int, but given parameters: (Object, String, int, float), and this result in runtime error which I was shown previously.

感谢

推荐答案

c> invokeExact 如果参数的编译时类型与 MethodHandle 的参数类型不匹配。它不利用通用结构来调用 cast 类< T> 上,动态类型仍然是编译器未知的。

You can’t use invokeExact if the compile-time type of an argument doesn’t match the MethodHandle’s parameter type. It doesn’t help to play around with the Generic constructs like invoking cast on a Class<T>, the dynamic type is still unknown to the compiler.

或者换句话说,由于类型擦除, tObj 仍然在字节代码级别 Object 。这是 MethodHandle 的调用类型。

Or, in other words, due to type erasure, the type of tObj is still Object on the byte code level. And this is the "invoked type" of the MethodHandle.

最简单的解决方案是使用调用而不是 invokeExact

The simplest solution is to use invoke rather than invokeExact.

想要使用 invokeExact ,是将 MethodHandle 转换为您最终将调用的类型,即更改类型第一个参数 Object

The only thing you can do if you want to use invokeExact, is to transform the MethodHandle to the type which you will eventually invoke, i.e. change the type of the first parameter to Object:

myMH=myMH.asType(myMH.type().changeParameterType(0, Object.class));
// now it doesn’t matter that obj has compile-time type Object
assertEquals((int)myMH.invokeExact(obj, "addintaasdsa", 10, 20.0f), 12);

这篇关于InvokeExact对象,其类型由classloader动态加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆