動態載入不適合數組類?那如何動態載入一個數組類?
摘要:既然數組是一個類,那麼編譯後類名是什麼?類路徑呢?為什麼說動態載入不適合數組?那應該如何動態載入一個數組?
本文分享自華為雲社區《【JAVA冷知識】動態載入不適合數組類?那如何動態載入一個數組類?》,作者:山河已無恙。
- 今天和小夥伴分享一些java小知識點,主要圍繞下面幾點:
- 既然數組是一個類,
- 那麼編譯後類名是什麼?類路徑呢?
- 為什麼說動態載入不適合數組?
- 那應該如何動態載入一個數組?
- 部分內容參考
- 《編寫高品質程式碼(改善Java程式的151個建議)》
- 《深入理解Java虛擬機》
一、既然數組是一個類,那麼編譯後類名是什麼?
通下面的程式碼我們可以看出,對於基本類型數組,編譯後為[+基本類型標識,對於引用類型為[L+引用類類路徑
package com.liruilong; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: * @Author: [email protected] * @WeChat_Official_Accounts: 山河已無恙 * @blog: //liruilong.blog.csdn.net/ * @Date: 2022/2/9 3:08 */ public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main(String[] args) { logger.info("基本類型數組編譯後類名:" + int[].class.getName()); logger.info("引用類型數組編譯後類名:" + String[].class.getName()); } }
二月 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中數組是一個較為特殊的類,不管是基本類型數組,還是引用類型數組,都沒有可追溯的類路徑
數組元素類型及編譯後的類型
二、為什麼動態載入不適合數組
動態載入
關於動態載入,這裡不多講,相信小夥伴么都不陌生,在原始的JDBC編程連接資料庫的時候,通常會通過靜態塊動態的載入一個連接資料庫的驅動類,這裡會用到Class.forName(driver),將驅動類載入到記憶體中。
當然這裡forName只是把一個類載入到記憶體中,並不是產生一個實例對象,也不會執行任何方法,具體的注入的驅動類如何生成對象,如何註冊到DriverManager,一般可以通過靜態塊的方式實現,即類載入的同時生成實例對象並註冊。
我們知道在類載入(載入,驗證,準備,解析,初始化)的最後一步類初始化的時候,執行類構造器<clinit>()方法,<clinit>()方法是編譯器自動收集類中的所有類變數的賦值動作的和靜態語句塊的中的語句合併產生的。編譯器收集的順序是由語句中源文件中出現的順序決定。
下面是mysql驅動類的源碼
// // Source code recreated from a .class file by IntelliJ IDEA // (powered by Fernflower decompiler) // 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
package com.liruilong; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: * @Author: [email protected] * @WeChat_Official_Accounts: 山河已無恙 * @blog: //liruilong.blog.csdn.net/ * @Date: 2022/2/9 3:08 */ public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main(String[] args) throws ClassNotFoundException { Class.forName("java.lang.String[]"); Class.forName("int[]"); } } 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
直接載入不可以,那麼載入一個數組編譯後的類型是否可行呢?我們來看看
package com.liruilong; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: * @Author: [email protected] * @WeChat_Official_Accounts: 山河已無恙 * @blog: //liruilong.blog.csdn.net/ * @Date: 2022/2/9 3:08 */ public class ArrayDemo { static Logger logger = Logger.getAnonymousLogger(); public static void main(String[] args) throws ClassNotFoundException { Class.forName("[Ljava.lang.String;"); Class.forName("[I"); } } Bad level value for property: .level Bad level value for property: java.util.logging.ConsoleHandler.level Process finished with exit code 0
通過上面我們可以知道,可以載入編譯後的類路徑動態載入一個對象數組,但是沒有意義。並不能通過newInstance()方法生成一個實例對象,在java中數組是定長的,沒有長度的數組是不允許存在的。
package com.liruilong; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: * @Author: [email protected] * @WeChat_Official_Accounts: 山河已無恙 * @blog: //liruilong.blog.csdn.net/ * @Date: 2022/2/9 3:08 */ 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(); } } 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數組工具類來動態載入一個數組。
package com.liruilong; import java.lang.reflect.Array; import java.util.logging.Logger; /** * @Project_name: workspack * @Package: com.liruilong * @Description: * @Author: [email protected] * @WeChat_Official_Accounts: 山河已無恙 * @blog: //liruilong.blog.csdn.net/ * @Date: 2022/2/9 3:08 */ 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); } }
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++之類的語言實現的
public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException { return newArray(componentType, length); } private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException;
關於數組的動態載入和小夥伴們分享到這裡,生活加油哦 ^_^