Class.forName与动态加载

Posted GaJa

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Class.forName与动态加载相关的知识,希望对你有一定的参考价值。

可以通过Class.forName("类的全类名")方法创建一个类的类类型。不仅如此,这个方法还表示了动态加载类。

动态加载类与静态加载类的区分:

  • 编译时刻加载的类称为静态加载类。
  • 运行时刻加载的类称为动态加载类。

 

静态加载的不足:在编译时就会把所有类都加载,不论是否使用

Office.java类

 1 class Office{
 2     public static void main(String args[]){
 3             if("Word".equals(args[0])){
 4                 Word word=new Word();
 5                 word.start();
 6             }
 7             if("Excel".equals(args[0])){
 8                 Excel excel=new Excel();
 9                 excel.start();
10             }
11     }
12 }

思考:这个程序是否能够通过编译?

Office.java:4: 错误: 找不到符号
                                Word word=new Word();
                                ^
  符号:   类 Word
  位置: 类 Office
Office.java:4: 错误: 找不到符号
                                Word word=new Word();
                                              ^
  符号:   类 Word
  位置: 类 Office
Office.java:8: 错误: 找不到符号
                                Excel excel=new Excel();
                                ^
  符号:   类 Excel
  位置: 类 Office
Office.java:8: 错误: 找不到符号
                                Excel excel=new Excel();
                                                ^
  符号:   类 Excel
  位置: 类 Office
4 个错误

 思考:毫无疑问肯定是编译失败的,因为Word、Excel类还没有定义,当然也不存在两个start()方法。正因为如此编译失败也就理所当然了,但是如果多考虑一点:Word用吗?Excel用吗?也许这两个类与两个方法都用不到,既然都不用,可是编译却无法通过。

Word.java:编写Word类和start方法

1 class Word {
2     public void start(){
3         System.out.println("Word...starts..");
4     }
5 }

继续编译这个程序:现在只报了两个关于Excel的错误。

 F:\xj>javac Word.java
 
 F:\xj>javac Office.java
 Office.java:8: 错误: 找不到符号
                                 Excel excel=new Excel();
                                 ^
   符号:   类 Excel
   位置: 类 Office
 Office.java:8: 错误: 找不到符号
                                 Excel excel=new Excel();
                                                 ^
   符号:   类 Excel
   位置: 类 Office
 2 个错误

 

思考:此刻再来思考和上面一样的问题,如果只需要Word,不需要Excel,但是这个程序也依然运行不了。因为程序做的是静态加载。即:new方式创建对象都是静态加载类

使用静态加载导致了不管这些类是否使用,在编译的时候就必须加载所有可能使用到的类。

 

然而在实际中,希望Word存在,Word就可以用;当用Excel的时候java编译器你再提醒我Excel有问题。就例如我们程序中有100个程序,但是只要是一个有了问题,其他的都用不了。其实这并不是我们想要看到的。这就是编译时加载导致的。所以希望利用运行时动态加载来解决该问题。

 

动态加载

通过new方法来创建对象都是静态加载,但是通过forName()方法去可以进行动态加载。

OfficeBetter.java:这里采用动态加载

 1 class OfficeBetter{
 2     public static void main(String args[]){
 3         try{
 4             //动态加载类在运行时刻。编译的时候并不会报错,他才不会管你是哪个类呢。
 5             Class classWord=Class.forName(args[0]);
 6         }catch(Exception e){
 7             e.printStackTrace();
 8         }
 9     }
10 }

问题:接下来创建对象又有了问题了,如果这里面使用Word word=(Word)classWord.newInstance(),此刻如果传入的是Excel就出现问题了;如果往Excel做强制类型转换,那么如果传入Word同样会出现问题。

思路:所以这里面要提升一下思想,给Word与Excel制定一个标准,然后让Word与Excel实现这个标准OfficeAble。完整代码如下:

OfficeBetter.java

 1 class OfficeBetter{
 2     public static void main(String args[]){
 3         try{
 4             Class class01=Class.forName(args[0]);        
 5             OfficeAble oa=(OfficeAble)class01.newInstance();
 6             oa.start();
 7         }catch(Exception e){
 8             e.printStackTrace();
 9         }
10     }
11     
12 }

OfficeAble.java:接口

1 interface OfficeAble{
2     public void start();
3 }

Word.java

1 class Word implements OfficeAble{
2     public void start(){
3         System.out.println("Word...starts..");
4     }
5 }

此刻编译都是完全可以通过, 然后我们分别输入Excel与word

F:\xj>java OfficeBetter Excel
java.lang.ClassNotFoundException: Excel
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at java.lang.Class.forName0(Native Method)
        at java.lang.Class.forName(Unknown Source)
        at OfficeBetter.main(OfficeBetter.java:5)

F:\xj>java OfficeBetter Word 

 发现:当输入Excel的时候才会发生错误,但是当输入Word的时候完全可以使用。
和之前的相比,不同的是,这里面编译的时候没有任何问题。word也可以正常使用。只有在输入Excel,开始运行Excel的时候才会报错——notFoundException。 这正是我们需要的动态加载:在编译的时候不去理会,在使用的时候再去判断。
接下来就可以创建对象了: 通过类类型创建该类的对象。

 运行结果:

F:\xj>javac OfficeBetter.java
F:\xj>java OfficeBetter Word
Word...starts.. 

 
当然类似Word类,也可以建一个Excel类:

class Excel implements OfficeAble{
    public void start(){
    System.out.println("Excel...starts..");
    }
}


F:\xj>javac Excel.java
F:\xj>java OfficeBetter Excel
Excel...starts...

 这里面OfficeBetter这个类不用再编译,直接运行就可以了

功能性的类一般使用动态加载,而不是静态加载

 

END.

以上是关于Class.forName与动态加载的主要内容,如果未能解决你的问题,请参考以下文章

Java - 如何用 Class.forName 加载外部 Jar 里的类文件?

动态加载类并实例化对象 —— newInstance

类加载与动态代理

Java 编程下使用 Class.forName() 加载类

java如何加载一个外部的类或class文件

理解Java的Class.forName()方法