反射学习笔记

类加载器

  • 程序使用某个类,系统会通过加载、连接、初始化三步来实现对这个类进行初始化
  • 何为加载:将class文件读入内存,并为之创建一个Class对象
  • 何为连接:
  1. 验证是否有正确内部结构,并和其他类协调一致
  2. 准备:负责为类的静态成员分配内存并设置默认初始化值
  3. 解析:将类的二进制数据中的符号引用替换为直接引用
  • 何为初始化:初始化步骤

类的初始化时机:

  • 创建实例时
  • 访问类的静态变量,或为其赋值
  • 调用静态方法
  • 使用反射创建某个类或接口的Class对象
  • 初始化某个类的子类
  • 直接使用java.exe命令来运行某个主类

三种类加载器

  • BootStrap ClassLoader根类加载器:负责java核心类加载(rt包中的核心类)
  • Extension ClassLoader扩展类加载器:负责JRE扩展目录中jar包的加载
  • System ClassLoader系统类加载器:负责在JVM启动时加载来自java命令的class文件,以及classpath所指定的jar包和类路径

反射的概念

  • 反射机制是运行状态中,对于任意类,都能调用其任意一个方法和属性,这种动态获取信息和调用对象的方法称为反射机制
  • 解剖一个类,需要先获取到每一个字节码文件对应的Class类型的对象
  • 先获取某个类的class类对象,然后通过这个Class对象去使用该文件中的成员变量、构造方法和成员方法

获取某个类的Class对象

  1. 方法1:Object类的getClass()方法
  2. 方法2:数据类型的静态成员变量class
  3. 方法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();
}

运行结果:
进入系统
增加
退出系统


进入系统
学习
退出系统

你可能感兴趣的:(反射学习笔记)