Java中我们一般会使用new关键字实例化对象然后调用该对象所属类提供的方法来实现相应的功能,比如我们现在有个主类叫Web类这个类中能实现各种方法,比如用户注册、发送邮件等功能,代码如下:
/*
* web功能实现类
*/
public class Web { public static void main(String[] args) {
//每次有新功能都需要重新加载
if("UserReg".equals(args[0])) {
UserReg ur = new UserReg();
ur.action();
}
if("SendEmail".equals(args[0])) {
SendEmail se = new SendEmail();
se.action();
} } }
上面的代码简单的通过命令行的参数进行功能的调用,当然扩展到web的url参数原理也完全一样,通过代码可以看到,我们需要调用某一个功能,则必须实例化该功能所在的对象,并且每当添加一个新功能时,必须再写一个if语句进行添加,并不能动态扩展;假设当我们只有UserReg类时,SendEmail类正在开发中,那么这两个功能都是无法使用的,因为如果实例化一个不存在的类时编译器会报错,代码根本无法通过编译。这些所说的就是Java的静态加载,静态加载的含义就是在程序的编译阶段进行加载,当出现任何类不存在或者方法不存在的错误时,编译都不通过,这就是Java中的静态加载
那么与静态加载相对应的动态加载的含义就是在程序运行时真正的执行代码,编译过程不进行任何检查,这样就避免了上面的问题,实现方式就是通过类的反射,我们改进上面的执行类为动态加载的,代码如下:
/*
* web功能实现类
* 动态加载举例
*/
public class Web { public static void main(String[] args) {
try {
Class<?> w = Class.forName("net.zengzhiying.dynamicloading." + args[0]);
IWeb i = (IWeb) w.newInstance();
i.action();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
} }
上面代码就是通过forName方法进行反射从而动态加载类,w就是对应类的类类型,同时也是Class的对象,所以从某种意义上来说,万事万物皆是对象,类也是对象,类对象和类的对象是严格区分的,类对象也就是类类型,那么使用类类型的newInstance方法可以创建该类类型的类的对象;另外为了解决每次实例化对象类都不同的问题,这里使用的父接口来统一声明,我们需要任何功能只需要实现IWeb接口即可,不同功能模块由不同的程序员实现也是没问题的,或者使用父类或者抽象类来统一声明,子类中进行方法的重写或实现也可以,总之这个地方就是利用的多态的思想来实现,IWeb接口代码如下:
public interface IWeb {
public void action();
}
那么我们现在实现其中的模块:
UserReg.java
public class UserReg implements IWeb { public void action() {
System.out.println("我实现了用户注册的功能!");
}
}
SendEmail.java
public class SendEmail implements IWeb {
public void action() {
System.out.println("我实现了发送电子邮件的功能");
}
}
以上这些代码通过编译是没有任何问题的,那么执行的时候我们使用命令行执行来传参数,eclipse不能直接执行,效果如下:
通过执行可以看到,很容易的通过参数实现了不同的功能操作,对于不存在的功能,那么很显然会抛出异常,因为编译阶段没有经过严格的验证,所以抛出异常也是必然的,实际开发中我们要进行恰当的异常处理,这样就用动态加载实现了功能模块的无限扩展,我们后来添加UserLogin用户登录模块或者添加UserLogout用户退出模块,完全不必要修改Web主类中所有的代码,只是都实现IWeb接口即可,这种动态加载类的思想在框架底层应用中也是经常用到的。