侧边栏壁纸
博主头像
Epoch

Java开发、Python爬虫、微服务、分布式、前端

  • 累计撰写 93 篇文章
  • 累计创建 110 个标签
  • 累计收到 8 条评论

目 录CONTENT

文章目录

Java反射(牛掰级别大白话+案例)

Epoch
2021-02-07 / 0 评论 / 0 点赞 / 302 阅读 / 2,241 字 / 正在检测是否收录...

什么是反射Reflect

反射(Reflect)是运行时动态访问类与对象的技术
反射是JDK1.2版本后的高级特性,隶属于java.lang.reflect
大多数Java框架都基于反射实现参数配置、动态注入等特性

反射的核心类

Class类
Constructor构造方法类
Method方法类
Field成员变量类

1、Class类

Class是JVM中代表"类和接口"的类

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

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

Class核心方法

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

怎么判断我们的Class对象是否被加载了呢?

通过静态代码块可以判断类是否被加载到jvm
package com.xmaven.reflect.entity;

/**
 * @ClassName User
 * @Description TODO 员工实体类
 * @Author Ambition
 * @Date 2021/2/7 16:44
 * @Version 1.0.0
 **/
public class User {

    /**
     * 通过静态代码块可以判断类是否被加载到jvm
     */
    static {
        System.out.println("User类已被加载到jvm,并且已经初始化");
    }

    private Integer id;
    public String username;
    private String password;
    private Float salary;
    private String dname;

    public User() {
        System.out.println("User默认的无参构造方法被执行了!");
    }

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

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    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 "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", salary=" + salary +
                ", dname='" + dname + '\'' +
                '}';
    }

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

编写demo

package com.xmaven.reflect;

import com.xmaven.reflect.entity.User;

/**
 * @ClassName ClassSample
 * @Description TODO
 * @Author Ambition
 * @Date 2021/2/7 16:52
 * @Version 1.0.0
 **/
public class ClassSample {

    public static void main(String[] args) {
        try {
            // Class.forName()方法将指定的类加载到jvm,并返回对应的Class对象
            Class<?> userClass = Class.forName("com.xmaven.reflect.entity.User");
            // newInstance通过默认构造方法创建新的对象
            User user = (User) userClass.newInstance();
            System.out.println(user);
        } catch (ClassNotFoundException e) {
            // 类名与类路径书写错误是抛出“类无法找到”异常
            e.printStackTrace();
        } catch (InstantiationException e) {
            // 对象无法实例化,抛出"实例化异常"
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // 非法访问异常,当在作用域外访问对象方法或成员变量时抛出异常
            e.printStackTrace();
        }

    }

}

2、Constructor构造方法类

Constructor类是对Java类中的构造方法的抽象

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

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

Constructor类核心方法

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

编写demo(注:公用一个实体类)

package com.xmaven.reflect;

import com.xmaven.reflect.entity.User;

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

/**
 * @ClassName ConstructorSample
 * @Description TODO 利用带参构造方法创建对象
 * @Author Ambition
 * @Date 2021/2/7 17:20
 * @Version 1.0.0
 **/
public class ConstructorSample {

    public static void main(String[] args) {
        try {
            Class<?> userClass = Class.forName("com.xmaven.reflect.entity.User");
            // 构造方法中的填写相应的类型,匹配我们对象里面的方法
            Constructor<?> constructor = userClass.getConstructor(new Class[]{
                    Integer.class, String.class, String.class, Float.class, String.class
            });
            // Obj[]数组中的参数需要和我们上面的参数类型填写一致才行
            User user = (User) constructor.newInstance(new Object[]{
                    100, "李磊", "root", 2001f, "文化部"
            });
            System.out.println(user);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            // 没有找到与之对应格式的方法
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            // 当被调用的方法的内部抛出了异常而没有被捕获的时候
            e.printStackTrace();
        }
    }

}

3、Method方法类

Method对象指代某个类中的方法的描述

Method对象使用classObj.getMethod()方法获取

通过Method对象调用指定对象的对应方法

Method类核心方法

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

编写demo(注:公用一个实体类)

package com.xmaven.reflect;

import com.xmaven.reflect.entity.User;

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

/**
 * @ClassName MethodSample
 * @Description TODO 利用Method方法类调用
 * @Author Ambition
 * @Date 2021/2/7 17:37
 * @Version 1.0.0
 **/
public class MethodSample {

    public static void main(String[] args) {
        try {
            Class<?> userClass = Class.forName("com.xmaven.reflect.entity.User");
            Constructor<?> constructor = userClass.getConstructor(new Class[]{
                    Integer.class, String.class, String.class, Float.class, String.class
            });
            User user = (User) constructor.newInstance(new Object[]{
                    1000, "张三", "root", 3800f, "研发部"
            });
            /**
             * 第一个里面参数是传入的方法名   里面可能有多个方法名相同的方法,参数不同
             * 第二个参数 传入我们需要的带参的方法的参数类型
             */
            Method updateSalaryMethod = userClass.getMethod("updateSalary", new Class[]{
                    Float.class
            });
            User newUser = (User) updateSalaryMethod.invoke(user, new Object[]{1000f});
            System.out.println(newUser);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

}

4、Field成员变量类

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

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

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

Field类核心方法

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

import com.xmaven.reflect.entity.User;

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

/**
 * @ClassName FieldSample
 * @Description TODO Field对成员变量进行赋值/取值
 * @Author Ambition
 * @Date 2021/2/7 18:01
 * @Version 1.0.0
 **/
public class FieldSample {

    public static void main(String[] args) {
        try {
            Class<?> userClass = Class.forName("com.xmaven.reflect.entity.User");
            Constructor<?> constructor = userClass.getConstructor(new Class[]{
                    Integer.class, String.class, String.class, Float.class, String.class
            });
            User user = (User) constructor.newInstance(new Object[]{
                    100, "李磊", "root", 2001f, "运维部"
            });
            // Field的赋值/取值操作
            Field usernameField = userClass.getField("username");
            usernameField.set(user,"张三");
            String username = (String) usernameField.get(user);
            System.out.println("username = " + username);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            // 没有找到成员变量类的异常
            e.printStackTrace();
        }
    }

}

getDeclared系列方法

getDeclaredConstructor(s)|Method(s)|Field(s)获取对应的对象

getConstructor(s)|Method(s)|Field(s)只能获取public对象

访问非作用域内构造方法、方法、成员变量,会抛出异常

编写demo

package com.xmaven.reflect;

import com.xmaven.reflect.entity.User;

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

/**
 * @ClassName GetDeclaredSample
 * @Description TODO 获取对象所有成员变量值
 * @Author Ambition
 * @Date 2021/2/7 18:19
 * @Version 1.0.0
 **/
public class GetDeclaredSample {

    public static void main(String[] args) {
        try {
            Class<?> userClass = Class.forName("com.xmaven.reflect.entity.User");
            Constructor<?> constructor = userClass.getConstructor(new Class[]{
                    Integer.class, String.class, String.class, Float.class, String.class
            });
            User user = (User) constructor.newInstance(new Object[]{
                    100, "李磊", "root", 2001f, "运维部"
            });
            // 获取当前类的所有成员变量
            Field[] fields = userClass.getDeclaredFields();
            for (Field field : fields) {
                if (field.getModifiers() == 1) { // public修饰
                    Object val = field.get(user);
                    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 = userClass.getMethod(methodName);
                    Object val = getMethod.invoke(user);
                    System.out.println(field.getName() + ":" + val);
                }
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

}

反射在项目中的应用案例

语言国际化简单demo

编写一个接口

package com.xmaven.i18n;

/**
 * @ClassName I18N
 * @Description TODO
 * @Author Ambition
 * @Date 2021/2/7 18:33
 * @Version 1.0.0
 **/
public interface I18N {

    public String say();

}

实现接口

package com.xmaven.i18n;

/**
 * @ClassName Zhcn
 * @Description TODO
 * @Author Ambition
 * @Date 2021/2/7 18:34
 * @Version 1.0.0
 **/
public class Zhcn implements I18N {
    @Override
    public String say() {
        return "生命不息奋斗不止";
    }
}

在工程的src目录下创建一个配置文件

config.properties

内容如下

language=com.xmaven.i18n.Zhcn

编写测试类:

package com.xmaven.i18n;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Properties;

/**
 * @ClassName Application
 * @Description TODO
 * @Author Ambition
 * @Date 2021/2/7 18:36
 * @Version 1.0.0
 **/
public class Application {

    public static void say(){
        Properties properties = new Properties();
        String configPath = Application.class.getResource("/config.properties").getPath();
        try {
            configPath = URLDecoder.decode(configPath, "UTF-8");
            properties.load(new FileInputStream(configPath));
            String language = properties.getProperty("language");
            I18N i18n = (I18N)Class.forName(language).newInstance();
            System.out.println(i18n.say());
        } catch (UnsupportedEncodingException | FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

    }

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

}
0

评论区