JNI字段描述符“([Ljava/lang/String;)V” --- 语法定义

本文详细介绍了Java Native Interface (JNI) 中使用的字段和方法描述符。包括如何表示基本类型、对象类型、数组类型以及如何组合这些描述符来表示复杂的方法签名。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    “([Ljava/lang/String;)V” 它是一种对函数返回值和参数的编码。这种编码叫做JNI字段描述符(JavaNative Interface FieldDescriptors)。一个数组int[],就需要表示为这样"[I"。如果多个数组double[][][]就需要表示为这样 "[[[D"。也就是说每一个方括号开始,就表示一个数组维数。多个方框后面,就是数组 的类型。

 

     如果以一个L开头的描述符,就是类描述符,它后紧跟着类的字符串,然后分号“;”结束。

 

     比如"Ljava/lang/String;"就是表示类型String;

 

     "[I"就是表示int[];

 

     "[Ljava/lang/Object;"就是表示Object[]。

 

     JNI方法描述符,主要就是在括号里放置参数,在括号后面放置返回类型,如下:

 

   (参数描述符)返回类型

 

    当一个函数不需要返回参数类型时,就使用”V”来表示。

 

    比如"()Ljava/lang/String;"就是表示String f();

 

    "(ILjava/lang/Class;)J"就是表示long f(int i, Class c);

 

    "([B)V"就是表示void String(byte[] bytes);

 

Java 类型

符号

Boolean

Z

Byte

B

Char

C

Short

S

Int

I

Long

J

Float

F

Double

D

Void

V

objects对象

以"L"开头,以";"结尾,中间是用"/" 隔开的包及类名。比如:Ljava/lang/String;如果是嵌套类,则用$来表示嵌套。例如 "(Ljava/lang/String;Landroid/os/FileUtils$FileStatus;)Z"

 

     另外数组类型的简写,则用"["加上如表A所示的对应类型的简写形式进行表示就可以了,比如:[I 表示 int [];[L/java/lang/objects;表示Objects[],另外。引用类型(除基本类型的数组外)的标示最后都有个";"

 

     例如:

 

             "()V" 就表示void Func();

 

             "(II)V" 表示 void Func(int, int);

 

             "(Ljava/lang/String;Ljava/lang/String;)I".表示 int Func(String,String)

<think>好的,用户的问题是关于在Android应用中调用隐藏API时被拒绝,特别是使用Java的LambdaMetafactory的情况。首先,我需要回忆一下Android隐藏API的限制。从Android 9(API 28)开始,Google对非公开API的使用进行了限制,导致反射或JNI等方法访问这些API时会抛出错误,比如NoSuchMethodException或AccessDeniedException。 用户提到使用LambdaMetafactory,这可能是因为他们试图通过方法句柄来动态生成lambda表达式,进而访问隐藏API。但即使这样,Android的系统限制仍然可能阻止这种访问。我需要考虑解决方案的几个方向:绕过限制、适配公开API、使用系统权限或系统应用签名。 首先,反射和JNI绕过是常见的方法,但需要处理每个Android版本的兼容性问题,尤其是Android 9及以上。比如,使用反射调用setAccessible(true)可能在某些版本上失效,需要寻找替代方法。另外,双重反射(通过getDeclaredMethod获取setAccessible方法本身)可能绕过限制,但维护成本高。 其次,LambdaMetafactory本身在Android上的支持可能有限,特别是低版本。需要检查目标API级别,并考虑是否所有设备都兼容。此外,即使使用LambdaMetafactory,生成的方法句柄仍然可能触发系统的隐藏API检查,导致访问被拒。 另外,用户可能需要考虑是否有公开的API可以替代隐藏功能。例如,某些功能在较新的API级别中可能被开放,或者有官方推荐的实现方式。如果必须使用隐藏API,可能需要将应用声明为系统应用,或者使用系统签名,但这通常只适用于设备制造商或定制ROM的情况。 还有用户提到的修改注册表的方法,看起来是从Windows环境下的解决方案,可能不适用于Android。需要指出这一点,避免用户误操作。 最后,生成相关问题时,需要覆盖用户可能关心的其他方面,比如不同Android版本的差异、官方替代方案、LambdaMetafactory的具体用法,以及成为系统应用的具体步骤。这样可以帮助用户全面了解问题,并找到最适合他们的解决方案。</think>在Android应用中调用隐藏API时被拒绝的问题,通常是由于Google从Android 9(API 28)开始实施的"非公开API限制政策"导致的[^1]。以下是针对使用LambdaMetafactory访问隐藏API的解决方案: ### 分步解决方案 1. **绕过限制检测机制** - 通过反射修改`VMRuntime`状态: ```java Class<?> vmRuntimeClass = Class.forName("dalvik.system.VMRuntime&quot;); Method getRuntimeMethod = vmRuntimeClass.getDeclaredMethod("getRuntime&quot;); Object vmRuntime = getRuntimeMethod.invoke(null); Method setHiddenApiExemptions = vmRuntimeClass.getDeclaredMethod("setHiddenApiExemptions", String[].class); setHiddenApiExemptions.invoke(vmRuntime, (Object) new String[]{"L"}); ``` 2. **适配Android版本差异** - Android 10+需要额外处理: ```java if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { Field field = ActivityThread.class.getDeclaredField("mHiddenApiWarningShown&quot;); field.setAccessible(true); field.setBoolean(null, true); } ``` 3. **LambdaMetafactory的特殊处理** ```java MethodHandles.Lookup lookup = MethodHandles.lookup(); MethodType methodType = MethodType.methodType(void.class); MethodHandle handle = lookup.findConstructor(HiddenClass.class, methodType); CallSite site = LambdaMetafactory.metafactory( lookup, "run", MethodType.methodType(Runnable.class), MethodType.methodType(void.class), handle, MethodType.methodType(void.class) ); Runnable r = (Runnable) site.getTarget().invokeExact(); ``` ### 注意事项 1. **兼容性风险**:反射方案在Android 12及以上版本可能失效[^1] 2. **替代方案**:优先使用`@SystemApi`标注的公开API 3. **系统应用适配**:在`AndroidManifest.xml`中添加: ```xml <manifest xmlns:android="http://schemas.android.com/apk/res/android" coreApp="true" android:sharedUserId="android.uid.system"> ``` ### 引用说明 修改VMRuntime状态的方案来源于Android ART虚拟机源码分析,LambdaMetafactory的异常处理参考了Oracle官方文档对方法句柄的解释[^2]。系统应用签名方案需要设备厂商配合[^3]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值