类加载器
- 程序使用某个类,系统会通过加载、连接、初始化三步来实现对这个类进行初始化
- 何为加载:将class文件读入内存,并为之创建一个Class对象
- 何为连接:
- 验证是否有正确内部结构,并和其他类协调一致
- 准备:负责为类的静态成员分配内存并设置默认初始化值
- 解析:将类的二进制数据中的符号引用替换为直接引用
- 何为初始化:初始化步骤
类的初始化时机:
- 创建实例时
- 访问类的静态变量,或为其赋值
- 调用静态方法
- 使用反射创建某个类或接口的Class对象
- 初始化某个类的子类
- 直接使用java.exe命令来运行某个主类
三种类加载器
- BootStrap ClassLoader根类加载器:负责java核心类加载(rt包中的核心类)
- Extension ClassLoader扩展类加载器:负责JRE扩展目录中jar包的加载
- System ClassLoader系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath所指定的jar包和类路径
反射的概念
- 反射机制是运行状态中,对于任意类,都能调用其任意一个方法和属性,这种动态获取信息和调用对象的方法称为反射机制
- 解剖一个类,需要先获取到每一个字节码文件对应的Class类型的对象
- 先获取某个类的class类对象,然后通过这个Class对象去使用该文件中的成员变量、构造方法和成员方法
获取某个类的Class对象
- 方法1:Object类的getClass()方法
- 方法2:数据类型的静态成员变量class
- 方法3:Class.forName(""),类名称必须为带包名的类全称
开发过程优先选方法3,可通过配置文件动态加载类
获取某个类的构造方法Construor对象
Constructor[] cons = c4.getConstructors();
//获取所有公共构造方法对象
Constructor[] cons2 = c4.getDeclaredConstructors();
//获取所有构造方法对象
Constructor cons3 = c4.getConstructor();
//获取无参数构造方法对象
Constructor cons4 = c4.getConstructor(String.class, int.class);
//获取某个有参数构造方法
Constructor cons5 = c4.getDeclaredConstructor(String.class, int.class, String.class);
cons5.setAccessible(true);
//获取私有构造方法
- 创建实例:
Object obj = cons3.newInstance();
//通过无参数构造方法对象来获取对象实例
Object obj2 = cons4.newInstance("刘耕",29);
//通过有参数构造方法对象来获取对象实例
获取某个类的成员变量Field对象
Object personLiu = cons5.newInstance("刘耕", 29, "成都");
Field address = c4.getField("address"); //获取指定名字的成员变量对象
Object obj = address.get(personLiu);
//获取某对象成员变量的值
System.out.println(obj);
address.set(personLiu, "重庆");
//通过反射方法,对某对象的成员变量进行复制
obj = address.get(personLiu);
System.out.println(obj);
结果显示:
成都
重庆
获取某个类的成员方法Method对象
Method m1 = c4.getMethod("show", null);
//通过方法名字和所需要传入的参数的class对象,来获取Method对象
m1.invoke(personLiu, null);
//通过Method对象调用该方法
Method m2 = c4.getMethod("getString", String.class,int.class);
System.out.println(m2.invoke(personLiu, "我是刘庚",28));
//通过反射调用有参数成员方法并获取返回值
结果显示:
show:name=刘耕,age=29,address=重庆;
我是刘庚---28
思考:
这个例子中的反射未使用泛型,想想如果使用泛型会有哪些不同?
通过反射运行配置文件
在java工程中设置配置文件,将需要动态加载的类名称设置在配置文件中
Properties prop = new Properties();
//通过Properties对象解析配置文件
FileReader fr = new FileReader("class.txt");
prop.load(fr);
//加载相应文件的输入流
fr.close();
String className = prop.getProperty("className");
//读取配置文件中定义的类名
Constructor consFile = Class.forName(className).getConstructor(String.class, int.class);
Object obj = consFile.newInstance("刘耕",28);
System.out.println(obj);
注意:配置文件必须放置在java工程目录下
反射应用
反射的应用十分广泛
写一个方法,将某对象中名为PropertyName属性的值进行赋值
public void setProperty(Object obj, String propertyName, Object value) throws Exception, SecurityException {
Class objClass = obj.getClass();
Field objField = objClass.getDeclaredField(propertyName);
objField.setAccessible(true);
objField.set(obj, value);
}
动态代理
程序运行过程中生成动态代理
public class Test {
public static void main(String[] args) {
UserDao ud = new UserDaoImpl();
Student st = new NewStudent();
MyInvocationHandler udhandler = new MyInvocationHandler(ud);
MyInvocationHandler sthandler = new MyInvocationHandler(st);
UserDao userDaoProxy = (UserDao)Proxy.newProxyInstance(ud.getClass().getClassLoader(), ud.getClass().getInterfaces(),udhandler);
Student studentProxy = (Student)Proxy.newProxyInstance(st.getClass().getClassLoader(), st.getClass().getInterfaces(),sthandler);
//获得的对象是进过修饰的代理对象,将原对象的方法进行了修饰
userDaoProxy.add();
System.out.println("--------------------");
studentProxy.study();
}
}
public class MyInvocationHandler implements InvocationHandler{
private Object target;
public MyInvocationHandler(Object target) {
this.target = target;
//指定需要代理的对象
}
@Override
public Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable {
System.out.println("进入系统");
Object obj = arg1.invoke(target, arg2);
//利用反射调用需要代理的对象的方法
System.out.println("退出系统");
//对需要代理的对象中的方法进行修饰
return obj;
}
}
public interface UserDao {
public abstract void add();
public abstract void find();
public abstract void update();
public abstract void delete();
}
public class UserDaoImpl implements UserDao{
@Override
public void add() {
System.out.println("增加");
}
@Override
public void find() {
System.out.println("查找");
}
@Override
public void update() {
System.out.println("修改");
}
@Override
public void delete() {
System.out.println("删除");
}
}
public class NewStudent implements Student{
@Override
public void study() {
// TODO Auto-generated method stub
System.out.println("学习");
}
@Override
public void play() {
// TODO Auto-generated method stub
System.out.println("玩耍");
}
}
public interface Student {
public abstract void study();
public abstract void play();
}
运行结果:
进入系统
增加
退出系统
进入系统
学习
退出系统