将 JObject 转换为 JList

Casting a JObject to a JList

JObject转换为JList(或其他任何东西,没关系,这只是一个例子),只是做JList(MyJobject)的好方法吗?我没有收到任何错误,但我不确定这样做是否正确。

在不同对象类型之间进行转换时,不能使用普通 type-cast。您必须将 JObject 转换为 ILocalObject 并调用其 GetObjectID() 方法,然后将该结果传递给目标 class 类型的 Wrap() 方法,在此案例TJList,例如:

例如:

var
  MyJobject: JObject;
  MyJList: JList;

MyJobject := ...;
MyJList := TJList.Wrap((MyJobject as ILocalObject).GetObjectID);

或更简单(这只是上面的包装):

var
  MyJobject: JObject;
  MyJList: JList;

MyJobject := ...;
MyJList := TJList.Wrap(MyJobject);

What the purpose of doing (MyJobject as ILocalObject).GetObjectID

使用普通类型转换可能会出现两个问题。

首先,如果特定的Java class没有用之前的Delphi代码初始化,它的VMT table将不会被初始化。接下来,JNI 调用返回的引用是本地引用,它们仅在特定本机方法的持续时间内有效。

JNI tips

Every argument passed to a native method, and almost every object returned by a JNI function is a "local reference". This means that it's valid for the duration of the current native method in the current thread. Even if the object itself continues to live on after the native method returns, the reference is not valid.

This applies to all sub-classes of jobject, including jclass, jstring, and jarray. (The runtime will warn you about most reference mis-uses when extended JNI checks are enabled.)

The only way to get non-local references is via the functions NewGlobalRef and NewWeakGlobalRef.

If you want to hold on to a reference for a longer period, you must use a "global" reference. The NewGlobalRef function takes the local reference as an argument and returns a global one. The global reference is guaranteed to be valid until you call DeleteGlobalRef.

Wrap 解决了这两个问题。如果尚未初始化,它将初始化 Java class VMT,并将本地 JObject 引用转换为全局引用。

仅当 class 由某些先前的代码初始化并且本地引用未在检索所述引用的本机 (Delphi) 方法之外使用时,普通类型转换才有效。

这就是 JStringToString(JString(PurchaseDataList.get(I))) 中使用的普通类型转换可以正常工作的原因。 get 返回的 JObject 引用立即转换为 Delphi 字符串并且 JString VMT 在此时已经初始化,常用 Java class .

如有疑问,使用 Wrap 更安全,但也比普通类型转换花费更多时间。