若移动端访问不佳,请使用 –> Github Page 版
关键字:NoSuchMethodError
、System.arraycopy
、Native Method
0x00:奇怪的异常
应用新版本上线后观察错误日志,发现一个奇怪的 Crash 异常信息:
lang.java.NoSuchMethodError: (java.lang.System.arraycopy)
异常集中发生在 Android 4.4.2 和 Android 5.1 上面,System.arraycopy()
是一个系统函数,要说没这个方法倒是不会,但异常发生了,说明应用在找这个方法时发生了错误。
0x01:探究原因
根据异常日志,追踪到 System.arraycopy()
是 Base64.java 的 public static byte[] decode(byte[] source, int off, int len, int options)
方法里调用的。
经过查找 Android API 19~21 的系统源码,发现发生此问题的原因是 Android>=21 时,java.lang.System.arraycopy()
多了几个重载。
在 Android <=20 上:
//java.lang.System 只有一个 arraycopy 方法
public static native void arraycopy(Object src, int srcPos,Object dst, int dstPos, int length);
在 Android >=21 上:
//java.lang.System
public static native void arraycopy(Object src, int srcPos,Object dst, int dstPos, int length);
/**
* The byte[] specialized version of arraycopy().
*
* @hide internal use only
*/
public static void arraycopy(byte[] src, int srcPos, byte[] dst, int dstPos, int length){}
Base64.java 应该使用的是 native void arraycopy(Object src...
,但是会在 compileSdkVersion>=21
时使用重载的 arraycopy(byte[] src …
,那么运行在 Android <=20 的手机上时就会报 java.lang.NoSuchMethodError
的异常了。
总结下来就是:如果你在 Android 上使用了此 Base64 工具类,并且编译时使用的 Android 版本>=21,那么在低版本上你可能会遇到 java.lang.NoSuchMethodError: java.lang.System.arraycopy
的异常。之所以说是可能,是因为出现此异常时在开发平常的应用时不会发生,一般是使用修改后的系统
Jar 包调用系统隐藏方法时才容易出现。
0x02:解决方案
如何解决呢?有两个方法:
1.指定使用 arraycopy 使用的重载方法,避免编译器用错
System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
//替换成
System.arraycopy((Object) outBuff, 0, (Object) out, 0, outBuffPosn);
2.使用 Arrays.copyOf ()
来替代 System.arraycopy()
System.arraycopy(outBuff, 0, out, 0, outBuffPosn);
//替换成
out = Arrays.copyOf(outBuff, outBuffPosn);
虽然 Arrays.copyOf()
的方法实现最后还是调用的 System.arraycopy()
,但是不会调用到错误的重载方法。
PS:你可以通过下面的方式和我联系