上一个建议解释了为什么要使用forName,本建议就来说说哪些地方不适合使用动态加载。如果forName要加载一个类,那它首先必须是一个类——8个基本类型排除在外,它们不是一个具体的类;其次,它必须具有可追索的类路径,否则就会报ClassNotFoundException。
在Java中,数组是一个非常特殊的类,虽然它是一个类,但没有定义类路径,例如这样的代码:
public static void main(Stringargs)throws Exception{
Stringstrs=new String[10];
Class.forName("java.lang.String");
}
String是一个类型声明,它作为forName的参数应该也是可行的吧!但是非常遗憾,其运行结果如下:
Exception in thread"main"java.lang.ClassNotFoundException:java/lang/String
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at Client.main(Client.java:6)
产生ClassNotFoundException异常的原因是数组虽然是一个类,在声明时可以定义为String,但编译器编译后会为不同的数组类型生成不同的类,具体如表7-2所示。
在编码期,我们可以声明一个变量为String,但是经过编译器编译后就成为了[Ljava.lang.String。明白了这一点,再根据以上的表格可知,动态加载一个对象数组只要加载编译后的数组对象就可以了,代码如下:
//加载一个String数组
Class.forName("[Ljava.lang.String;");
//加载一个long数组
Class.forName("[J");
虽然以上代码可以动态加载一个数组类,但是这没有任何意义,因为它不能生成一个数组对象,也就是说以上代码只是把一个String类型的数组类和long类型的数组类加载到了内存中(如果内存中没有该类的话),并不能通过newInstance方法生成一个实例对象,因为它没有定义数组的长度,在Java中数组是定长的,没有长度的数组是不允许存在的。
既然反射不能定义一个数组,那问题就来了:如何动态加载一个数组呢?比如依据输入动态产生一个数组。其实可以使用Array数组反射类来动态加载,代码如下:
//动态创建数组
Stringstrs=(String)Array.newInstance(String.class,8);
//创建一个多维数组
intints=(int)Array.newInstance(int.class,2,3);
因为数组比较特殊,要想动态创建和访问数组,基本的反射是无法实现的,“上帝对你关闭一扇门,同时会为你打开另外一扇窗”,于是Java就专门定义了一个Array数组反射工具类来实现动态探知数组的功能。
注意 通过反射操作数组使用Array类,不要采用通用的反射处理API。