点击上方蓝字 江湖评谈设为关注/星标
前言
上一篇:.NET9引用数组协变怪异Bug里的问题,好奇Java有没有类似问题?结果看了下openjdk,发现还真有,而且似乎一模一样,本篇看下。因上一篇以最新的.NET9 RC2为蓝本,那么本篇以OpenJDK24为蓝本看下。
问题
老规矩,先上例子:
//filename:hellotest.java
import java.util.Scanner;
public class hellotest {
public static void main(String[] args) {
try {
// 创建一个 String 类型的数组
Object[] arr = new String[10];
// 尝试将一个 Integer 对象存储到 String 类型的数组中
arr[0] = new Integer(10); // 这里会抛出 ArrayStoreException
} catch (ArrayStoreException e) {
// 捕获 ArrayStoreException 异常并打印堆栈信息
System.out.println("Caught ArrayStoreException:");
e.printStackTrace();
Scanner scanner = new Scanner(System.in);
String input = scanner.nextLine();
}
}
}
Java版本及输出:
root@Tyz:~/link_openjdk# ./java --version
openjdk 24-internal 2025-03-18
OpenJDK Runtime Environment (slowdebug build 24-internal-adhoc.tang.jdksource)
OpenJDK 64-Bit Server VM (slowdebug build 24-internal-adhoc.tang.jdksource, mixed mode)
root@Tyz:~/link_openjdk# javac hellotest.java
root@Tyz:~/link_openjdk# ./java hellotest
Caught ArrayStoreException:
java.lang.ArrayStoreException: java.lang.Integer
at hellotest.main(hellotest.java:10)
Java.lang.ArrayStoreException 是 Java 的内置异常类,它位于 Java.lang 包中。java.lang 包是 Java 标准库的一个核心包,几乎所有的 Java 应用都会自动导入这个包,无需显式导入它。
java.lang.ArrayStoreException 是一个在 Java 中发生的运行时异常,它会在尝试将不兼容的元素存储到数组中时被抛出。这通常发生在数组的协变性(即数组类型的继承关系)导致类型不匹配的情况下。
这种处理方式跟dotnet是一模一样的。
分析
其实上面的问题已经很明显了,但这里依旧看下底层的运行方式。运行之后,我们附加下其pid:
root@Tyz:~/link_openjdk# ./java hellotest
Caught ArrayStoreException:
java.lang.ArrayStoreException: java.lang.Integer
at hellotest.main(hellotest.java:10)
重开一个终端:
root@Tyz:~# ps aux | grep hellotest
root 4370 54.7 2.3 3671476 94912 pts/0 Sl+ 10:44 0:05 ./java hellotest
root 4392 0.0 0.0 12368 2432 pts/1 S+ 10:44 0:00 grep --color=auto hellotest
root@Tyz:~# lldb -p 4370
Current symbol store settings:
-> Cache: /root/.dotnet/symbolcache
-> Server: https://msdl.microsoft.com/download/symbols/ Timeout: 4 RetryCount: 0
(lldb) process attach --pid 4370
Process 4370 stopped
* thread #1, name = 'java', stop reason = signal SIGSTOP
//中间省略,便于观看
(lldb) bt
* thread #1, name = 'java', stop reason = signal SIGSTOP
* frame #0: 0x00007fca2c498d61 libc.so.6`__GI___futex_abstimed_wait_cancelable64 at futex-internal.c:57:12
frame #1: 0x00007fca2c498d37 libc.so.6`__GI___futex_abstimed_wait_cancelable64 at futex-internal.c:87:9
frame #2: 0x00007fca2c498d10 libc.so.6`__GI___futex_abstimed_wait_cancelable64(futex_word=0x00007fca297ff990, expected=4371, clockid=<unavailable>, abstime=0x0000000000000000, private=<unavailable>) at futex-internal.c:139:10
frame #3: 0x00007fca2c49e793 libc.so.6`__pthread_clockjoin_ex(threadid=140506256373440, thread_return=0x00007ffdef5cbfb0, clockid=0, abstime=0x0000000000000000, block=<unavailable>) at pthread_join_common.c:102:14
frame #4: 0x00007fca2c75ccfa libjli.so`CallJavaMainInNewThread(stack_size=1048576, args=0x00007ffdef5cc050) at java_md.c:676:9
frame #5: 0x00007fca2c75b7cf libjli.so`ContinueInNewThread(ifn=0x00007ffdef5cc1e0, threadStackSize=1048576, argc=0, argv=0x00005a055aad0570, mode=1, what="hellotest", ret=0) at java.c:2314:16
frame #6: 0x00007fca2c75cda0 libjli.so`JVMInit(ifn=0x00007ffdef5cc1e0, threadStackSize=0, argc=0, argv=0x00005a055aad0570, mode=1, what="hellotest", ret=0) at java_md.c:701:12
frame #7: 0x00007fca2c7554ec libjli.so`JLI_Launch(argc=0, argv=0x00005a055aad0570, jargc=0, jargv=0x0000000000000000, appclassc=0, appclassv=0x0000000000000000, fullversion="24-internal-adhoc.tang.jdksource", dotversion="0.0", pname="java", lname="openjdk", javaargs='\0', cpwildcard='\x01', javaw='\0', ergo=0) at java.c:324:12
frame #8: 0x00005a055a014671 java`main(argc=2, argv=0x00007ffdef5cf3f8) at main.c:184:12
frame #9: 0x00007fca2c42a1ca libc.so.6`__libc_start_call_main(main=(java`main at main.c:58:1), argc=2, argv=0x00007ffdef5cf3f8) at libc_start_call_main.h:58:16
frame #10: 0x00007fca2c42a28b libc.so.6`__libc_start_main_impl(main=(java`main at main.c:58:1), argc=2, argv=0x00007ffdef5cf3f8, init=(_rtld_global), fini=<unavailable>, rtld_fini=<unavailable>, stack_end=0x00007ffdef5cf3e8) at libc-start.c:360:3
frame #11: 0x00005a055a014205 java`_start + 37
(lldb)
glibc main入口运作下的一个缩影
结尾
感觉语言趋同之势越来越明显,但本篇这个问题似乎十几年前就趋同了。
往期精彩回顾