君子不妄动,动必有道。君子不徒语,语必有理。君子不苟求,求必有义。君子不虚行,行必有正 ——烽火戏诸侯《剑来》
写在前面
今天和小伙伴分享一些java
小知识点,主要围绕下面几点:
既然数组
是一个类,
那么编译后类名
是什么?类路径
呢?
为什么说动态加载
不适合数组
?
那应该如何动态加载
一个数组
?
部分内容参考
《编写高质量代码(改善Java程序的151个建议)》
《深入理解Java虚拟机》
君子不妄动,动必有道。君子不徒语,语必有理。君子不苟求,求必有义。君子不虚行,行必有正 ——烽火戏诸侯《剑来》
一、既然数组
是一个类,那么编译后类名
是什么?
通下面的代码我们可以看出,对于基本类型数组,编译后为[+基本类型标识
,对于引用类型为[L+引用类类路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 package com.liruilong;import java.util.logging.Logger;public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main (String[] args) { logger.info("基本类型数组编译后类名:" + int [].class.getName()); logger.info("引用类型数组编译后类名:" + String[].class.getName()); } }
1 2 3 4 5 6 二月 09, 2022 3:57:03 上午 com.liruilong.ArrayDemo main 信息: 基本类型数组编译后类名:[I 二月 09, 2022 3:57:03 上午 com.liruilong.ArrayDemo main 信息: 引用类型数组编译后类名:[Ljava.lang.String; Process finished with exit code 0
在java
中数组是一个较为特殊的类,不管是基本类型数组
,还是引用类型数组
,都没有可追溯的类路径
数组元素类型及编译后的类型
元素类型
编译后的类型
byte[]
[B
char[]
[C
Double[]
[D
Float[]
[F
Int[]
[I
Long[]
[J
Short[]
[S
Boolean
[Z
引用类型(如String)
[L引用类型
二、为什么动态加载不适合数组 动态加载 关于动态加载,这里不多讲,相信小伙伴么都不陌生,在原始的JDBC编程
连接数据库的时候,通常会通过静态块动态的加载一个连接数据库的驱动类,这里会用到Class.forName(driver)
,将驱动类加载到内存中。
当然这里forName
只是把一个类加载
到内存中
,并不是产生一个实例对象
,也不会执行任何方法
,具体的注入的驱动类如何生成对象,如何注册到DriverManager
,一般可以通过静态块
的方式实现,即类加载的同时生成实例对象并注册
。
我们知道在类加载(加载,验证,准备,解析,初始化)
的最后一步类初始化
的时候,执行类构造器<clinit>()方法
,<clinit>()方法
是编译器自动收集
类中的所有类变量的赋值动作
的和静态语句块的中的语句
合并产生的。编译器收集的顺序是由语句中源文件中出现的顺序决定。
下面是mysql驱动类的源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 package com.mysql.jdbc;import java.sql.DriverManager;import java.sql.SQLException;public class Driver extends NonRegisteringDriver implements java .sql .Driver { public Driver () throws SQLException { } static { try { DriverManager.registerDriver(new Driver()); } catch (SQLException var1) { throw new RuntimeException("Can't register driver!" ); } } }
为什么不适合数组 关于动态加载,小伙伴可以看看《深入理解Java虚拟机》
,回到我们的问题,为什么数组不适合动态加载,由上面的代码可以知道,当使用forName
加载一个类时,需要一个类的全路径
,或者说全限定名
。
但是不管是基本类型数组
,还是引用类型数组
,都没有可追溯的类路径,不是一个具体的类,所以在加载的时候,会报错java.lang.ClassNotFoundException
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.liruilong;import java.util.logging.Logger;public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main (String[] args) throws ClassNotFoundException { Class.forName("java.lang.String[]" ); Class.forName("int[]" ); } }
1 2 3 4 5 6 Exception in thread "main" java.lang.ClassNotFoundException: java/lang/String[] at java.lang.Class.forName0(Native Method) at java.lang.Class.forName(Class.java:264) at com.liruilong.ArrayDemo.main(ArrayDemo.java:19) Process finished with exit code 1
直接加载不可以,那么加载一个数组编译后的类型是否可行呢?我们来看看
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.liruilong;import java.util.logging.Logger;public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main (String[] args) throws ClassNotFoundException { Class.forName("[Ljava.lang.String;" ); Class.forName("[I" ); } }
1 2 3 4 Bad level value for property: .level Bad level value for property: java.util.logging.ConsoleHandler.level Process finished with exit code 0
通过上面我们可以知道,可以加载编译后的类路径动态加载一个对象数组,但是没有意义。并不能通过newInstance()
方法生成一个实例对象,在java中数组是定长的,没有长度的数组是不允许存在的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 package com.liruilong;import java.util.logging.Logger;public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main (String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Class<String[]> aClass = (Class<String[]>) Class.forName("[Ljava.lang.String;" ); String[] strings = aClass.newInstance(); } }
1 2 3 4 5 6 7 8 9 10 11 Bad level value for property: .level Bad level value for property: java.util.logging.ConsoleHandler.level Exception in thread "main" java.lang.InstantiationException: [Ljava.lang.String; at java.lang.Class.newInstance(Class.java:427) at com.liruilong.ArrayDemo.main(ArrayDemo.java:20) Caused by: java.lang.NoSuchMethodException: [Ljava.lang.String;.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.newInstance(Class.java:412) ... 1 more Process finished with exit code 1
三、如何动态加载一个数组
那如何通过类似动态加载的方式生成一个数组,我们可以使用Array数组工具类来动态加载一个数组。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 package com.liruilong;import java.lang.reflect.Array;import java.util.logging.Logger;public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main (String[] args) { String [] strings = (String[]) Array.newInstance(String.class,6 ); logger.info("String数组长度:" +strings.length); int [][] ints = (int [][])Array.newInstance(int .class,6 ,3 ); logger.info("int数组长度:" +ints.length); } }
1 2 3 4 5 6 7 8 9 Bad level value for property: .level Bad level value for property: java.util.logging.ConsoleHandler.level Can't set level for java.util.logging.ConsoleHandler 二月 09, 2022 5:15:12 上午 com.liruilong.ArrayDemo main 信息: String数组长度:6 二月 09, 2022 5:15:12 上午 com.liruilong.ArrayDemo main 信息: int数组长度:6 Process finished with exit code 0
看看源码,我们会发现这是一个本地方法,通过C或者C++之类的语言实现的
1 2 3 4 public static Object newInstance (Class<?> componentType, int length) throws NegativeArraySizeException { return newArray(componentType, length); }
1 2 private static native Object newArray (Class<?> componentType, int length) throws NegativeArraySizeException ;
关于数组的动态加载和小伙伴们分享到这里,生活加油哦 ^_^