本帖最后由 瞧瞧嗨一波... 于 2017-12-21 17:59 编辑
类装载器(ClassLoader):
定义:ClassLoader就是寻找类的字节码文件,并构造出类在JVM内部表示的对象组件。JVM运行时产生三个ClassLoader:根装载器、ExtClassLoader(扩展类装载器)、AppClassLoader(系统类装载器)。根装载器并不是ClassLoader的子类(由C++编写),ExtClassLoader和AppClassLoader都是ClassLoader的子类
ExtClassLoader:负责装载JRE扩展目录ext中的JAR类包
AppClassLoader:负责装载ClassPath路径下的类包
根装载器:负责装载JRE的核心类库,比如:rt.jar、charsets.jar;
ClassLoader将一个类装入JVM需要以下步骤:
1.装载:查找和导入Class文件;
2.链接:执行校验、准备和解析步骤,其中解析步骤是可选的:
a.校验:检查载入Class文件数据的正确性;
b.准备:给类的静态文件分配存储空间;
c.解析:将符号引用转成直接引用;
3.初始化:对类的静态变量和静态代码块执行初始化工作。
ClassLoader重要方法:
Class loadClass(String name):装载
Class loadClass(String name, boolean resolve):重载,resolve是否需要解析,并不是所有类在初始化的时候都要解析的
Class defineClass(String name, byte[], int off, int len):将类问件的字节数组转换成JVM内部的java.lang.Class对象
Class findSystemClass(String name):从本地文件系统加载一个Class问件,如果文件不存在就抛出ClassNotFoundException异常,JVM默认的装载机制
Class findLoadedClass(String name):查看ClassLoader是否装载了某个类
ClassLoader getParent():获取类装载器的父装载器。
java.lang.NoSuchMethodError:是由于JVM的全盘委托机制导致的,出现情景一般在:同时引用了commons-lang 2.x.jar 和 commons-lang 3.x.jar,JVM加载类时从commons-lang 2.x.jar中加载类,而代码中使用的却是commons-lang 3.x.jar中的方法,该方法在commons-lang 2.x.jar中并没有,此时,就会抛出该异常。
举例说明使用方法:
/** 测试实体 */
public class User{
private String name;
//默认构造器
public User(){}
//带参构造器
public User(String name){ this.name = name;}
public String getName(){ return this.name; }
public void setName(String Name){ this.name = name;}
public void talk(){ System.out.println("hello, my name is " + this.name);}
}
/** 测试方法 */
public class test{
private User initUser()throws Thtowable{
//通过类装载器获取User对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Calss clazz = loader.loadClass("com.taobao.entity.User");
//获取类的默认构造器对象并通过它实例化User
Constructor cons = clazz.getDeclaredConstructor((class[])null);
User user = (User)cons.newInstance();
//通过反射方法设置属性
Method setName = clazz.getMethod("setName", String.class);
setName.invoke(user, "老王");
return user;
}
public static void main(String[] args) throws Thtowable{
User user = this.initUser();
user.talk();
}
}
反射机制(reflect):
定义:Class反射对象描述类语意结构,可以从Class对象中获取构造函数、成员变量、方法等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义。
最主要的三个反射类:
Constructor:类的构造方法的反射类,通过Class.getConstructor()方法可以获得类的所有构造函数反射对象数组。在JDK5.0中,可以通过getConstrustor(Class parameterTypes)获取拥有特定参数的构造函数反射对象。Construstor主要方法是newInstance(Object[] initargs),创建一个对象实例。
Method:类方法的反射类,通过Class.getDeclaredMethod()方法可以获得类的所有方法反射对象数组Method[] 。在JDK5.0中,可以通过getDeclaredMethod(String name, Class parameterTypes)获取拥有特定参数的构造函数反射对象。Method主要方法是:
invoke(Object obj, Object...args):操作目标对象
Class getReturnType():获取方法返回值类型
Class[] getParameterTypes():获取方法的入参类型数组
Class[] getExceptionTypes():获取方法的异常类型数组
Annotation[][] getParameterAnnotations() :获取方法的注解信息,JDK5.0中的新方法
Field:类的成员变量的反射类,通过Class.getDeclaredFields()方法可以获得类的成员变量反射对象数组,通过Class.getDeclaredField(String name)可以获取某个特定成员对象的放射对象,Field主要方法:
set(Object obj, Object value):操作目标对象,通过value为目标对象的成员变量设置值
setBoolean(Object obj, boolean value);setInt(Object obj, int value);带类型名的值设置方法
举例说明使用方法:
/** 测试实体 */
public class PrivateUser{
//私有成员变量,外部不可引用
private String name;
//受保护成员方法,只有子类和本包中可以访问
protected void talk(){ System.out.println("hello, my name is " + this.name);}
}
/** 测试方法 */
public class test{
private User initUser()throws Thtowable{
//通过类装载器获取User对象
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Calss clazz = loader.loadClass("com.taobao.entity.PrivateUser");
//实例化User
PrivateUser user = (PrivateUser)clazz.newInstance();
//获取名为name的成员变量的反射对象
Field nameFld = clazz.getDeclaredField("name");
//获取名为talk的成员方法的反射对象
Method talkMtd = clazz.getDeclaredMethod("talk", (Class[]null));
/*Method talkMtd = clazz.getDeclaredMethod("talk"); JDK5.0下使用*/
//取消Java语言访问检查以访问private变量
nameFld.setAccessible(true);
nameFld.set(user, "老王");
//取消Java语言访问检查以访问protected方法
talkMtd.setAccessible(true);
talkMtd.invoke(user, (Object[]null));
}
} |
|