java反射笔记

本文深入探讨了Java反射机制,介绍了如何通过Class类加载和实例化对象,调用构造方法、成员方法和成员变量。通过示例展示了如何在运行时动态操作类和对象,包括使用Constructor、Method和Field类。此外,还展示了在实际项目中的应用,如I18n国际化,如何根据配置文件动态加载实现类。
摘要由CSDN通过智能技术生成

基础介绍

java虚拟机会在第一次使用一个类时将它加载到内存中,并创建该类的一个Class对象,这个Class对象只会创建一次。显然这个对象中包含了类的字段、构造方法、方法等信息。这是理解反射的关键。

Class类是反射的核心类,它主要有以下方法:

Class xxxClass = Class.forName(xxx类的完全限定类名); 加载指定类,并返回该类的Class对象的引用

xxx xxxInstance = xxxClass.newInstance(); 使用默认构造方法创建该类的一个实例

如果我们在程序运行时输入类名,那就可以在程序运行时决定实例化哪个类的对象,而不是一开始写死在程序中(编译阶段就已经确定要实例化哪个类的对象)。

Constructor xxxConstructor = xxxClass.getConstructor(new Class[]{Integer.class, String.class, ........}); 获取指定参数形式的构造方法。

.class和forName的区别:当类已经加载过了,可以使用.class获取类的Class对象。

xxx xxxInstance = (xxx) xxxConstructor.newInstance(new Object[]{v1, v2, ......}); 使用构造方法创建对象。

Method method = xxxClass.getMethod(方法名, new Class[]{Integer.class, ......}); 获取指定方法

method.invoke(xxxInstance, new Object[]{v1, v2, ......}); 执行方法,参数为执行方法的对象和方法所需参数的数组。

基础用法演示

实体类:

/**
 * 员工实体类
 */
public class Employee {
    static {
        System.out.println("Employee类已被加载到jvm,并已初始化");
    }
    private Integer eno;
    public String ename;
    private Float salary;
    private String dname;

    public Employee(){
        System.out.println("Employee默认构造方法已被执行");
    }

    public Employee(Integer eno,String ename,Float salary , String dname){
        this.eno = eno;
        this.ename = ename;
        this.salary = salary;
        this.dname = dname;
        System.out.println("Employee带参构造方法已被执行");
    }

    public Integer getEno() {
        return eno;
    }

    public void setEno(Integer eno) {
        this.eno = eno;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Float getSalary() {
        return salary;
    }

    public void setSalary(Float salary) {
        this.salary = salary;
    }

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "eno=" + eno +
                ", ename='" + ename + '\'' +
                ", salary=" + salary +
                ", dname='" + dname + '\'' +
                '}';
    }

    public Employee updateSalary(Float val){
        this.salary = this.salary + val;
        System.out.println(this.ename + "调薪至" + this.salary + "元");
        return this;
    }
}

Class类:

public class ClassSample {
    public static void main(String[] args) {
        try {
            //Class.forName()方法将指定的类加载到jvm,并返回对应Class对象
            //如果一个类以被加载到虚拟机,可以通过.class的方式获取它的Class对象
            Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
            System.out.println("Employee已被加载到jvm");
            //newInstance通过默认构造方法创建新的对象
            Employee emp = (Employee)employeeClass.newInstance();
            System.out.println(emp);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
            //类名与类路径书写错误是抛出"类无法找到"异常
            // 对象无法被实例化,抛出"实例化异常"
            // 非法访问异常,当在作用域外访问对象方法或成员变量时抛出
            e.printStackTrace();
        }


    }
}

构造方法类:

/**
 * 利用带参构造方法创建对象
 */
public class ConstructorSample {
    public static void main(String[] args) {
        try {
            Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
            Constructor<?> constructor = employeeClass.getConstructor(Integer.class,String.class,Float.class,String.class);
            Employee employee = (Employee) constructor.newInstance(new Object[]{
                    100,"李磊",3000f,"研发部"
            });
            System.out.println(employee);
        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            //没有找到与之对应格式的方法
            // 当被调用的方法的内部抛出了异常而没有被捕获时
            e.printStackTrace();
        }
    }
}

成员方法类:

/**
 * 利用Method方法类调用
 */
public class MethodSample {
    public static void main(String[] args) {
        try {
            Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
            Constructor<?> constructor = employeeClass.getConstructor(Integer.class,String.class,Float.class,String.class);
            Employee employee = (Employee)constructor.newInstance(new Object[]{
                    100,"李磊",3000f,"研发部"
            });
            Method updateSalaryMethod = employeeClass.getMethod("updateSalary" , Float.class);
            Employee employee1 = (Employee)updateSalaryMethod.invoke(employee,new Object[]{1000f});
            System.out.println(employee1);
        } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

成员变量类:

/**
 * 利用Field对成员变量赋值/取值
 */
public class FieldSample {
    public static void main(String[] args) {
        try {
            Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
            Constructor<?> constructor = employeeClass.getConstructor(Integer.class,String.class,Float.class,String.class);
            Employee employee = (Employee) constructor.newInstance(new Object[]{
                    100,"李磊",3000f,"研发部"
            });
            Field enameField = employeeClass.getField("ename");
            enameField.set(employee,"李雷");
            String ename = (String)enameField.get(employee);
            System.out.println("ename:" + ename);
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
            //没有找到对应成员变量时抛出的异常
            e.printStackTrace();
        }
    }
}

一般来说,以上示例中的普通get方法只能获取公有的成员和方法,不能获取私有的成员和方法。所以需要getDeclared方法.总结如下:

以下演示了getDeclaredFields方法,获取所有成员变量

/**
 * 获取对象所有成员变量值
 */
public class getDeclaredSample {
    public static void main(String[] args) {
        try {
            Class<?> employeeClass = Class.forName("com.imooc.reflect.entity.Employee");
            Constructor constructor = employeeClass.getConstructor(Integer.class, String.class, Float.class, String.class);
            Employee employee = (Employee) constructor.newInstance(new Object[]{
                    100, "李磊", 3000f, "研发部"
            });
            //获取当前类所有成员变量,包括私有
            Field[] fields = employeeClass.getDeclaredFields();
            for(Field field : fields){
//                System.out.println(field.getName());
                if(field.getModifiers() == 1){ //pubilc修饰
                    //成员变量类的get方法,获取成员变量值
                    Object val = field.get(employee);
                    //成员变量类的getName方法,获取成员变量名
                    System.out.println(field.getName() + ":" + val);
                }else if(field.getModifiers() == 2){ //private修饰
                    String methodName = "get" + field.getName().substring(0,1).toUpperCase()
                                        + field.getName().substring(1);
                    Method getMethod = employeeClass.getMethod(methodName);
                    Object ret = getMethod.invoke(employee);
                    System.out.println(field.getName() + ":" + ret);
                }
            }
        } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

项目应用:I18n国际化

配置文件config.properties:

language=com.imooc.i18n.En

I18n接口:

public interface I18N {
    public String say();
}

中文实现类:

public class Zhcn implements I18N {
    @Override
    public String say() {
        return "生命不息奋斗不止";
    }
}

英文实现类:

public class En implements I18N {
    @Override
    public String say() {
        return "Cease to the struggle and cease to the life";
    }
}

应用程序:

public class Application {
    public static void say(){
        //Properties,持久属性集合,接收配置文件信息
        Properties properties = new Properties();
        //获取配置文件完整文件路径,路径中的汉字会进行URL编码
        String configPath = Application.class.getResource("/config.properties").getPath();
        System.out.println(configPath);
        try {
            //解码,还原路径中的汉字;由于编码时应该采用的是UTF-8规则,所以解码也用该规则
            configPath = URLDecoder.decode(configPath,"UTF-8");
            System.out.println(configPath);
            //获取到文件路径后,先打开该文件,也即创建该文件的流
            //使用Property的load方法从流中加载属性信息
            properties.load(new FileInputStream(configPath));
            //获取key为language的value值,key和value都是String类型的
            String language = properties.getProperty("language");
            //我们写在配置文件中的值是类的路径,所以用反射直接加载就行了
            I18N i18n = (I18N)Class.forName(language).newInstance();
            //获取了I18N对象后,调用它的say方法
            System.out.println(i18n.say());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        Application.say();
    }
}

如果想输出中文,修改配置文件中的类路径就可以了,不用修改源代码.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值