我试图在Java中将一个类作为隐藏类加载,但遇到了VerifyError.这个类使用一个VarHandle,它有一个PolymorphicSignature.我认为这个错误暗示着多态调用正在使用非隐藏类,但我不清楚该如何修复它.定义包含对方法句柄或VarHandles调用的隐藏类的正确方式是什么?

package foo;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.VarHandle;
import java.util.function.IntUnaryOperator;
import org.junit.jupiter.api.Test;

public class HiddenClassTest {

  @Test
  public void loadHidden() throws Exception {
    MethodHandles.Lookup lookup;
    try (var is = IntThing.class.getResourceAsStream("HiddenClassTest$IntThing.class")) {
      lookup =
          MethodHandles.lookup().defineHiddenClass(is.readAllBytes(), true);
    }
    var instance =
        lookup.lookupClass()
            .asSubclass(IntUnaryOperator.class)
            .getConstructor()
            .newInstance();
    System.out.println(instance.applyAsInt(12));
    System.out.println(instance.applyAsInt(24));
  }

  static final class IntThing implements IntUnaryOperator {
    static final VarHandle IDX;

    static {
      try {
        IDX = MethodHandles.lookup().findVarHandle(IntThing.class, "idx", int.class);
      } catch (Exception e) {
        throw new RuntimeException(e);
      }
    }

    private int idx;

    @Override
    public int applyAsInt(int newIdx) {
      int oldIdx = (int) IDX.getOpaque(this);
      IDX.setOpaque(this, newIdx);
      return oldIdx;
    }
  }
}

错误:

Bad type on operand stack
Exception Details:
  Location:
    foo/HiddenClassTest$IntThing+0x0000000800d38c00.applyAsInt(I)I @4: invokevirtual
  Reason:
    Type 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' (current frame, stack[1]) is not assignable to 'foo/HiddenClassTest$IntThing'
  Current Frame:
    bci: @4
    flags: { }
    locals: { 'foo/HiddenClassTest$IntThing+0x0000000800d38c00', integer }
    stack: { 'java/lang/invoke/VarHandle', 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' }
  Bytecode:
    0000000: b200 072a b600 0d3d b200 072a 1bb6 0013
    0000010: 1cac                                   

java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    foo/HiddenClassTest$IntThing+0x0000000800d38c00.applyAsInt(I)I @4: invokevirtual
  Reason:
    Type 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' (current frame, stack[1]) is not assignable to 'foo/HiddenClassTest$IntThing'
  Current Frame:
    bci: @4
    flags: { }
    locals: { 'foo/HiddenClassTest$IntThing+0x0000000800d38c00', integer }
    stack: { 'java/lang/invoke/VarHandle', 'foo/HiddenClassTest$IntThing+0x0000000800d38c00' }
  Bytecode:
    0000000: b200 072a b600 0d3d b200 072a 1bb6 0013
    0000010: 1cac                                   

    at java.base/java.lang.ClassLoader.defineClass0(Native Method)
    at java.base/java.lang.System$2.defineClass(System.java:2307)
    at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClass(MethodHandles.java:2439)
    at java.base/java.lang.invoke.MethodHandles$Lookup$ClassDefiner.defineClassAsLookup(MethodHandles.java:2420)
    at java.base/java.lang.invoke.MethodHandles$Lookup.defineHiddenClass(MethodHandles.java:2127)
    at foo.HiddenClassTest.loadHidden(HiddenClassTest.java:16)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:568)
    at org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:725)
    at org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)

推荐答案

您是对的:这是因为多态签名,其中this会导致对签名中不同类的引用.解决方法是将thisObject显式强制转换为签名中的Ljava/lang/Object;,而不是LHiddenClassTest$IntThing;

int oldIdx = (int) IDX.getOpaque((Object) this);
IDX.setOpaque((Object) this, newIdx);
return oldIdx;

Java相关问答推荐

让两个方法来回调用有缺点吗?

Analyst Idea构建错误:NoClassDefFound错误:javax/html/bind/JAVAX Bwitch [SOLVED]

将@ManyToOne JPA Composite Key用作Id保存实体添加额外参数

当耗时的代码完成时,Circular ProgressIndicator显示得太晚

如何使用CSS为选定但未聚焦的表格行设置背景 colored颜色 ?

是否需要关闭Executors返回的执行器.newVirtualThreadPerTaskExecutor()?

在Java中将Charsequence数组更改为String数组或List String<>

方法没有用正确的值填充数组—而是将数组保留为null,'

如何转换Tue Feb 27 2024 16:35:30 GMT +0800 String至ZonedDateTime类型""

JDK22执行repackage of goal org. springframework. boot:spring—boot—maven—plugin:3.2.3:repackage failed:unsupported class file major version 66—>

Junit with Mockito for java

只需最少的代码更改即可将版本号标记添加到日志(log)

为什么JAVA&S清洁器使用链表而不是并发HashSet?

Spring Data JPA慢慢地创建了太多非活动会话

buildDir:File!&#的getter解决方案是什么?39.被抛弃

Android应用程序为错误的显示类型 Select 尺寸文件

无法将GSON导入到我的JavaFX Maven项目

循环不起作用只有第一个元素重复

TinyDB问题,无法解析符号';上下文&

如何判断元素计数并在流的中间抛出异常?