您的位置 首页 java

[JAVA冷知识]为什么动态加载不适合数组?如何动态加载一个数组?

写在前面


  • 今天和小伙伴分享一些 java 小知识点,主要围绕下面几点:
  • 既然 数组 是一个类,
  • 那么编译后 类名 是什么? 类路径 呢?
  • 为什么说 动态加载 不适合 数组
  • 那应该如何 动态加载 一个 数组 ?
  • 部分内容参考 《编写高质量代码(改善Java程序的151个建议)》《 深入理解Java虚拟机

君子不妄动,动必有道。君子不徒语,语必有理。君子不苟求,求必有义。君子不虚行,行必有正 ——烽火戏诸侯《 剑来


一、既然数组是一个类,那么编译后类名是什么?

 package com.liruilong;

import java.util.logging.Logger;

/**
 * @Project_name: workspack
 * @Package: com.liruilong
 * @Description:
 * @Author: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: 
 * @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 中数组是一个较为特殊的类,不管是 基本类型数组 ,还是 引用类型数组 ,都没有可追溯的类路径

数组元素类型及编译后的类型

元素类型

编译后的类型

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>()方法 编译器自动收集 类中的 所有类变量的赋值动作 的和 静态语句块的中的语句 合并产生的。编译器收集的顺序是由语句中源文件中出现的顺序决定。

下面是my SQL 驱动类的源码

 //
// 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.SQL Exception ;

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: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: 
 * @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: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: 
 * @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: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: 
 * @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.get Constructor 0(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: 1224965096@qq.com
 * @WeChat_Official_Accounts: 山河已无恙
 * @blog: 
 * @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;
  

关于数组的动态加载和小伙伴们分享到这里,生活加油哦 _

文章来源:智云一二三科技

文章标题:[JAVA冷知识]为什么动态加载不适合数组?如何动态加载一个数组?

文章地址:https://www.zhihuclub.com/180087.shtml

关于作者: 智云科技

热门文章

网站地图