1. 程式人生 > 其它 >動態載入不適合陣列類?那如何動態載入一個數組類?

動態載入不適合陣列類?那如何動態載入一個數組類?

摘要:既然陣列是一個類,那麼編譯後類名是什麼?類路徑呢?為什麼說動態載入不適合陣列?那應該如何動態載入一個數組?

本文分享自華為雲社群《【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: https://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: https://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: https://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: https://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: https://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;

關於陣列的動態載入和小夥伴們分享到這裡,生活加油哦 ^_^

點選關注,第一時間瞭解華為雲新鮮技術~