1、现象
1.1 问题场景
最近,在写测试代码时,将一个类(这里暂且称为ClassA)放在在缺省包中,也就是说,直接放在了src目录下,没有创建包。然后,将这个类打入了jar文件,提供给另外的工程(这里称为ProjA)用,结果发现了非常神奇的现象。
在ProjA中,如果从缺省包中引用ClassA,可以引用到。但是,如果创建一个包,在包中引用ClassA就会发现,引用不到,报错类找不到。第一反应是,是不是需要import啊?想写一个import语句。但是,由于ClassA放在缺省包中,也没法通过import包的方式引用这个类(因为没有包名)。这就比较尴尬了。
搜了下,发现不只是jar包中存在这个问题。这是java的一个普遍现象:Java在其它包中无法引用缺省包中的类。
1.2 机制解析
其实,细想一下,这个也比较好理解。因为如果在包中不指定报名引用一个类,一般是引用同一个包中的类。直觉上,我们可能会认为,如果在同一个包中找不到的这个类,java应该取缺省包看看,找下缺省包中是否能够找到这个类。然而,令人失望的是java现在没有这个机制(当然,也有可能是因为引入这个机制之后,会导致混乱。嗯,这个原因的可能性非常大。。。)。
2、解决方法
这里解决的方法也算是比较容易。大家在写java代码时,一定要注意尽量将类放在一个显式指定的包中,不要直接扔在缺省包中。
上面的方法适用于事前控制。如果情况已经出了,那么该如何在其他包中访问缺省包中的类呢?答案就是在于java的反射机制。
2.1 反射介绍
在Java语言中,可以通过如下的反射机制调用一个类的方法。具体如下:
首先通过反射获得指定类对应的Class对象
Class c = Class.forName("被调用类名");
获得指定类中的方法(通过传入方法名、参数类型等确认)
Method method= c.getMethod("被调用方法名", new Class[] { 参数列表类型 });
通过invoke方法,传入执行方法的类实例和方法参数,完成方法调用
Object value = method.invoke(class.newInstance(), new Object[]{ new String("参数一"),new String("参数二")});
如果要调用的方法是类的静态方法,就不需要传入实例,实例指定为null即可。
Object value = method.invoke(null, new Object[]{ new String("参数一"),new String("参数二")});
比如,想调用的类名为MyClass,其中有方法为String myMethod(String str1,String str2);则调用如下:
Class class = Class.forName("MyClass");
Method method= snmpHandler.getMethod("myMethod", new Class[] { String.class,String.class });
String value = method.invoke(class.newInstance(), new Object[]{ new String("str1"), new String("str2")});
//如果是静态方法
//String value = method.invoke(null, new Object[]{ new String("str1"), new String("str2")});
2.2 例子
先上代码:
HelloWorld.java:
/**
* Created by chengxia on 2019/4/13.
*/
public class HelloWorld {
public static void helloWorld(String name, String words){
System.out.println("Below is the output of HelloWorld class in the Default package.");
System.out.println(name + " said: " + words);
}
}
代码的工程结构如下图。
Test Module Structure
(1) CallHelloWorld1.java
package com.util.call;
/**
* Created by chengxia on 2019/4/13.
*/
public class CallHelloWorld1 {
public static void main(String []args){
HelloWorld.helloWorld("Kobe", "Mamba out!");
}
}
CallHelloWorld1类在包com.util.call中,当其引用HelloWorld类时,报错找不到,如下图。
Cannot Find Class in Default Package
这里为了下面的测试能够正常运行,在下面将报错的这行注释掉了。
(2) CallHelloWorld0.java
/**
* Created by chengxia on 2019/4/13.
*/
public class CallHelloWorld0 {
public static void main(String []args){
HelloWorld.helloWorld("Kobe", "Mamba out!");
}
}
CallHelloWorld0由于也在缺省包,所以可以正常引用HelloWorld类。运行如下:
Below is the output of HelloWorld class in the Default package.
Kobe said: Mamba out!
Process finished with exit code 0
(3) CallHelloWorld2.java
package com.util.call;
import java.lang.reflect.Method;
/**
* Created by chengxia on 2019/4/13.
*/
public class CallHelloWorld2 {
public static void main(String []args){
try
{
Class c = Class.forName("HelloWorld");
Method m = c.getMethod("helloWorld", new Class[]{String.class, String.class});
m.invoke(null, new Object[]{new String("Kobe"), new String("Mamba out!")});
}catch(Exception e){
e.printStackTrace();
}
}
}
CallHelloWorld2类在包com.util.call中,为了能正常调用HelloWorld类的方法,用了反射。可以正常运行,如下。
Below is the output of HelloWorld class in the Default package.
Kobe said: Mamba out!
Process finished with exit code 0
参考资料