反射

2022/8/6 23:23:28

本文主要是介绍反射,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

反射:运行时动态访问类与对象的技术

创建对象的时间 从编译时变成运行时

反射的作用:

package fnshe;
/**
*接口
/
public interface Math {
   public float ss(float a,float b);
}
package fnshe;

/**
 *ADD实现
 **/
public class ADD implements Math{
    @Override
    public float ss(float a, float b) {
        return a+b;
    }
}
package fnshe;

/**
 *实现接口
 **/
public class CHEN implements Math{
    @Override
    public float ss(float a, float b) {
        return a*b;
    }
}
package fnshe;

/**
 *实现接口
 **/
public class CHU implements Math {
    @Override
    public float ss(float a, float b) {
        if(b!=0){
            return a/b;
        }else {
            throw new RuntimeException("出书不能为0");
        }

    }
}
package fnshe;

/**
 *实现接口
 **/
public class JIAN implements Math{
    @Override
    public float ss(float a, float b) {
        return a-b;
    }
}
package fnshe;

import java.util.Scanner;

/**
 *操作类
 **/
public class Application {
    public void caozuo() throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Scanner scanner = new Scanner(System.in);
        String op = scanner.nextLine();
        float a=scanner.nextFloat();
        float b=scanner.nextFloat();
        Math o=(Math)Class.forName("fnshe."+op).newInstance();//动态创建对象
        System.out.println(o.ss(a, b));
    }

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        Application application = new Application();
        application.caozuo();
    }
}

反射的四个核心类

1.Class类

2.Constructor构造方法类

3.Method类

4.Field成员变量类

Class是JVM中代表”类和接口“的类

Class对象具体包含了某个特定类的结构信息

通过Class对象可获取对应类的构造方法/方法/成员变量

Class类核心方法

方法 用途
Class.forName() 静态方法,用于获取指定Class对象
classObj.newInstance() 通过默认构造方法创建新的对象
classObj.getConstructor() 获得指定的public修饰构造方法Constructor对象
classObj.getMethod() 获取指定的public修饰方法Method对象
classObj.getFiled() 获取指定的public修饰成员变量Field对象

Constructor构造方法类

Constructor类时对java类中的构造方法的抽象

Contructor对象包含了具体类的某个构造方法的声明

通过Constructor对象调用带参构造方法创建对象

核心方法

方法 用途
classObject.getConstructor() 获取指定public修饰的构造方法对象
constructorObj.newInstance() 通过对应的构造方法创建对象

Method方法类

方法 用途
classObj.getMethod() 获取指定public修饰的方法对象
methodObj.invoke() 调用指定对象的对应方法

Field成员变量类

Field对应某个具体类中的成员变量的声明

Field对象使用classObj.getField()方法获取

通过Field对象可为某对象成员变量赋值/取值

方法 用途
classObj.getField() 获取指定public修饰的成员变量
fieldObj.set() 为某对象指定成员变量赋值
fieldObj.get() 获取某对象指定成员变量数值

getDeclared系列方法

getDeclaredConstructors(s)|method(s)|Field(s)获取对应对象

访问非作用域,会抛出异常

代码

package reflect.entity;

import javax.jws.soap.SOAPBinding;

/**
 *Employee类
 **/
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.salary+"元");
        return this;
    }
}
package reflect;

import reflect.entity.Employee;

/**
 *创建对象
 **/
public class ClassSample {
    public static void main(String[] args) {
        //Class.forName()方法将指定的类加载到jvm,并返回对应Class对象
        //employeeClass包含reflect.entity.Employee所有成员
        try {
            Class employeeClass=Class.forName("reflect.entity.Employee");
            System.out.println("Employee已被加载到jvm");
            //newInstance()通过默认构造器创建新的对象
           Employee employee= (Employee)employeeClass.newInstance();
            /**
             * 执行结果
             * Employee类已经被加载到jvm,并初始化
             * Employee已被加载到jvm
             * Employee默认方法被执行...
             */
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            //实例化异常,抽象类,接口
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            //访问权限异常,当在作用域外访问对象方法或成员变量时抛出
            e.printStackTrace();
        }

    }
}
package reflect;

import reflect.entity.Employee;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 *构造反方法
 **/
public class ConstructorSample {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class employeeClass=Class.forName("reflect.entity.Employee");
        //选定特定构造器
        Constructor constructor = employeeClass.getConstructor(new Class[]{
                Integer.class, String.class, Float.class, String.class
        });
        //给构造器传值
        Employee employee = (Employee)constructor.newInstance(new Object[]{
                100, "李磊", 300f, "研发部"
        });
        System.out.println(employee);//Employee{eno=100, ename='李磊', salary=300.0, dname='研发部'}
    }
}
package reflect;

import reflect.entity.Employee;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 方法
 **/
public class MethodSample {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class employeeClass=Class.forName("reflect.entity.Employee");
        Constructor constructor = employeeClass.getConstructor(new Class[]{
                Integer.class, String.class, Float.class, String.class
        });
        Employee employee = (Employee)constructor.newInstance(new Object[]{
                100, "李磊", 300f, "研发部"
        });
        System.out.println(employee);
        //选择特定方法
        Method updateSalary = employeeClass.getMethod("updateSalary", new Class[]{Float.class
        });
        //执行方法
        Employee employee1 = (Employee)updateSalary.invoke(employee,new Object[]{1000f});
        System.out.println(employee1);
        /**
         * 执行结果
         * Employee类已经被加载到jvm,并初始化
         * Employee带参方法被执行...
         * Employee{eno=100, ename='李磊', salary=300.0, dname='研发部'}
         * 调整薪资为1300.0元
         * Employee{eno=100, ename='李磊', salary=1300.0, dname='研发部'}
         */

    }
}
package reflect;

import reflect.entity.Employee;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 成员变量
 **/
public class FieldSample {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class employeeClass=Class.forName("reflect.entity.Employee");
        Constructor constructor = employeeClass.getConstructor(new Class[]{
                Integer.class, String.class, Float.class, String.class
        });
        Employee employee = (Employee)constructor.newInstance(new Object[]{
                100, "李磊", 300f, "研发部"
        });
        System.out.println(employee);
        //public修饰
        Field enameField = employeeClass.getField("ename");
        enameField.set(employee,"李雷");
        String ename = (String)enameField.get(employee);
        System.out.println("ename="+ename);
    }
}
package reflect;

import reflect.entity.Employee;

import java.io.File;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *非public成员变量
 **/
public class getDeclaredSample {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class employeeClass=Class.forName("reflect.entity.Employee");
        Constructor constructor = employeeClass.getConstructor(new Class[]{
                Integer.class, String.class, Float.class, String.class
        });
        Employee employee = (Employee)constructor.newInstance(new Object[]{
                100, "李磊", 300f, "研发部"
        });
        Field[] fields = employeeClass.getDeclaredFields();
        for (Field f:fields){
            if(f.getModifiers()==1){
                //public修饰
                Object o = f.get(employee);
                System.out.println(f.getName()+":"+o);
            }else if(f.getModifiers()==2){
                //private修饰
                //拼装方法名getXxx
                String methodNames="get"+f.getName().substring(0,1).toUpperCase()+f.getName().substring(1);
                Method method = employeeClass.getMethod(methodNames);
                //这边不能强转
                Object invoke = method.invoke(employee);
                System.out.println(f.getName()+":"+invoke);
            }
        }

    }
}

关于Class类的getResource().getPath()方法

程序中配置文件如果放置在classes文件夹,那么我们就可以使用Class类的getResource().getPath()方法获取文件路径。

例如:

String path = DBUtil.class.getResource("/db.properties").getPath();

值得注意的文件是,如果发布程序的web容器(tomcat)安装的路径中存在空格

D:\Program Files\Apache Software Foundation\Tomcat 8.5

该方法将会得到URLEncode后的路径,类似这样。

D:/Program%20Files/Apache%20Software%20Foundation/Tomcat%208.5/

用上面这个绝对路径去获取所需要的文件的话,就会取不到文件。

比较稳妥的做法是将path进行一次URLDecode

path = URLDecoder.decode(path, chartset);


这篇关于反射的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程