类加载器:
从java开发人员角度来看,类加载器包括以下几种:
启动(Bootstrap)类加载器:负责将 Java_Home/lib下面的类库加载到内存中(比如rt.jar)。由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用,所以不允许直接通过引用进行操作。该类加载器由c/c++编写,通过getClassLoader()获取类加载器引用为空值null.
标准扩展(Extension)类加载器:是由 Sun 的 ExtClassLoader(sun.misc.Launcher$ExtClassLoader)实现的。它负责将Java_Home /lib/ext或者由系统变量 java.ext.dir指定位置中的类库加载到内存中。开发者可以直接使用标准扩展类加载器。
应用程序(Application)类加载器:是由 Sun 的 AppClassLoader(sun.misc.Launcher$AppClassLoader)实现的.它负责将系统类路径(CLASSPATH)中指定的类库加载到内存中.由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,因此一般称为系统(System)加载器.负责加载用户类路径定义的类库.可以通过Class.getSystemClassLoader()或自己编写的类.getClassLoader()来获取,一般自己没有定义别的类加载器,这个就是默认类加载器.
双亲委派模型:
![](https://img-blog.csdn.net/20170404180324802?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2l0aHViXzM4MTQ3NjU2/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
双亲委派模型的工作过程:类加载器在收到类加载的请求后将请求委托给自己的父加载器(!!!!!非继承,通过getParent()方法获取父加载器),一层一层往上传,直到启动类加载器.当父加载器无法处理该请求时,子加载器才会自己处理这个请求.因为判断两个类是否相等不仅与类自己的定义有关,还与加载该类的类加载器有关,同一个类由不同的类加载器加载,会被判断为不同的类.通过双亲委派模型可以避免这种情况.
public class Test {
public static void main(String[] args) {
ClassLoader c = Test.class.getClassLoader();
while (c != null) {
System.out.println(c.getClass().getName());
c = c.getParent();
}
}
}
这段代码通过getParent()方法迭代获取了类加载器,因为启动类加载器获取为null,所以看不到启动类加载器.
反射就是由用户主动在运行期间动态加载类的一种机制.主要用到了java.lang.Class和java.lang.ClassLoader以及java.lang.reflect.*来实现反射.通过反射可以通过配置文件来动态加载类,还可以破坏类的封装性访问类的私有属性和私有方法.
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class c = Thread.currentThread().getContextClassLoader().loadClass("rTest");
// Class c = Class.forName("rTest");
Object rtest = c.newInstance();
Method[] methods = c.getMethods();
Field[] fields = c.getFields();
for (Method m : methods) {
// System.out.println(m);
if (m.getName().equals("c")) {
m.invoke(rtest, new Object[]{});
}
if (m.getName().equals("d")) {
m.invoke(rtest, new Object[]{3, 4});
}
}
for (Field f : fields) {
System.out.println(f.get(rtest));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class rTest{
public int a = 0;
private int b = 0;
public void c() {
System.out.println("c");
}
public void d(int a, int b) {
this.a = a;
this.b = b;
System.out.println(a + b);
}
private void e() {
System.out.println("e");
}
}
这是一个反射的简单例子,可以通过ClassLoader的loadClass()方法和Class.forName()来加载类.使用Class的getMethods()和getField()方法来获取方法和属性,但是这样不能获取私有的方法和属性,要获取私有的方法和属性,要用getDeclaredMethods()和getDeclaredField()来获取.关于其他的用法可以看api文档.