Java反射机制

概述

  • 反射机制的作用
    通过java语言的反射机制可以操作字节码文件(.class)
  • 相关的类
    java.lang.Class 代表整个类的字节码
    java.lang.reflect.Method 代表类中方法的字节码
    java.lang.reflect.Constructor 代表类中构造方法的字节码
    java.lang.reflect.Field 代表类中属性的字节码

获取class的三种方式

要操作类的字节码,首先要获取到类的字节码

  1. Class.forName(String className)
    Class类中的静态方法
    返回一个Class对象
    className是完整的类名带上包名
    forName在获取类时会运行类中的静态代码块
package com.wcy.code01;

/**
 * Class.forName获取类
 */
public class GetClassTest01 {
    public static void main(String[] args) {
        Class<?> c1 = null;
        Class<?> c2 = null;
        try {
        	//完整的类名加上包名
            c1 = Class.forName("com.wcy.code01.GetClassTest01");
            c2 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(c1);
        System.out.println(c2);
    }
}

在这里插入图片描述

  1. obj.getClass()
    通过对象来获取类
package com.wcy.code01;
import java.util.Date;

/**
 1. obj.getClass()获取类
 */
public class GetClassTest02 {
    public static void main(String[] args) {
        String s = new String(new char[]{'1', '2', '3'});
        Date d = new Date();
        Class<?> sc = s.getClass();
        Class<?> ds = d.getClass();
        System.out.println(sc);
        System.out.println(ds);
    }
}

在这里插入图片描述

  1. 类型使用class属性
    Java中无论什么类型都有class属性
package com.wcy.code01;

/**
 * 通过class属性来获取类
 */
public class GetClassTest03 {
    public static void main(String[] args) {
        Class<String> c1 = String.class;
        Class<Integer> c2 = int.class;
        Class<GetClassTest03> c3 = GetClassTest03.class;

        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
    }
}
  1. 以上三种方式获取的类是一样的
    因为只会加载一个类在方法区中,无论通过何种方式获取,获取的都是同样的结果
package com.wcy.code01;

/**
 * 三种方法获取的类是一样的
 */
public class GetClassTest04 {
    public static void main(String[] args) {
        String s = "111";
        Class<?> c1 = null;
        Class<?> c2 = null;
        Class<?> c3 = null;

        try {
            c1 = Class.forName("java.lang.String");
            c2 = s.getClass();
            c3 = String.class;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        System.out.println(c1 == c2 && c2 == c3 && c1 == c3);

    }
}

在这里插入图片描述

通过反射机制实例化对象

  • newInstance() jdk8后弃用
  • 调用该方法会调用类中的无参构造方法来实例化对象
package com.wcy.code01;

public class NewInstanceTest01 {
    public static void main(String[] args) {
        try {
            Class<?> c1 = Class.forName("com.wcy.code01.User");

            //使用newInstance实例化对象
            Object o = c1.newInstance();
            System.out.println(o);
        } catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }
    }
}


class User {
    public User() {
        System.out.println("调用了无参构造方法!");
    }

}

在这里插入图片描述

使用反射机制实现使用配置文件实例化对象

通过读取配置文件中的内容来实例化对象,这样可以不用更改代码就可以实例化不同的对象。

配置文件中的内容

# 需要实例化的类 只需要更改此处的类名即可
classname=com.wcy.code01.User
package com.wcy.code01;

import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

/**
 * 使用配置文件实例化对象
 */
public class NewInstanceTest02 {
    public static void main(String[] args) {
        FileReader fileReader = null;
        Properties properties = null;
        try {
            //字符流读取配置文件
            fileReader = new FileReader("src/name.properties");
            //创建属性类对象map
            properties = new Properties();
            //加载配置文件
            properties.load(fileReader);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            //关闭配置文件读取
            if (fileReader != null) {
                try {
                    fileReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (properties != null) {
            //获取配置文件中的类名
            String className = properties.getProperty("classname");
            try {
                //获取类名实例化对象
                Class<?> c = Class.forName(className);
                Object o = c.newInstance();
                System.out.println(o);
            } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
}

在这里插入图片描述

反射机制获取属性

  • 基本方法
Field getField(String name)返回一个 Field对象,它反映此表示的类或接口的指定公共成员字段 类对象。
Field[] getFields()返回包含一个数组 Field对象反射由此表示的类或接口的所有可访问的公共字段 类对象。
Field getDeclaredField(String name)返回一个 Field对象,它反映此表示的类或接口的指定已声明字段和类对象。
Field[] getDeclaredFields()返回的数组 Field对象反映此表示的类或接口声明的所有字段 类对象。
package com.wcy.code02;


import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 反射机制获取属性
 */
public class ReflectField {
    public static void main(String[] args) throws Exception {
        Class<?> s = Class.forName("com.wcy.code02.User");
        //获取类中的所有public属性
        Field[] fields = s.getFields();
        System.out.println("属性个数" + fields.length);

        //获取名字
        System.out.println("属性信息:" + fields[0].getName());

        System.out.println("----------------------------------------");

        //获取所有的属性
        Field[] declaredFields = s.getDeclaredFields();
        System.out.println("属性个数" + declaredFields.length);
        for (Field field : declaredFields) {
            //获取属性类型
            Class<?> type = field.getType();
            String typeSimpleName = type.getSimpleName();
            //获取名字
            String fieldName = field.getName();
            //获取修饰符列表 返回的数字 需要转换
            int modifiers = field.getModifiers();
            //将数字代表的修饰符转换为字符串
            String modifiersString = Modifier.toString(modifiers);
            //打印所有的信息
            System.out.println(
                    "属性信息:" + typeSimpleName + "-->" + fieldName + "-->" + modifiersString
            );
        }
    }
}

在这里插入图片描述

通过反射机制还原java代码

  • 通过类名来获取属性,并还原java代码
package com.wcy.code02;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

/**
 * 通过反射机制来获取类中的属性
 * 并将反编译成标准的java代码
 */
public class ReflectField01 {
    public static void main(String[] args) throws Exception{
        //获取类
        Class<?> c = Class.forName("com.wcy.code02.User");
        //拼接字符串
        StringBuilder stringBuilder = new StringBuilder();
        //获取所有字段
        Field[] declaredFields = c.getDeclaredFields();

        //拼接类修饰符,类名,大括号
        stringBuilder.append(Modifier.toString(c.getModifiers()));
        stringBuilder.append(" class ");stringBuilder.append(c.getSimpleName());
        stringBuilder.append(" {\n");

        //拼接字段名
        for(Field field:declaredFields){
            stringBuilder.append("\t");
            stringBuilder.append(Modifier.toString(field.getModifiers()));

            //没有修饰符就不加空格
            if(!Modifier.toString(field.getModifiers()).equals("")) {
                stringBuilder.append(" ");
            }
            stringBuilder.append(field.getType().getSimpleName());
            stringBuilder.append(" ");
            stringBuilder.append(field.getName());
            stringBuilder.append(";\n");
        }

        //最后的大括号
        stringBuilder.append("}");
        System.out.println(stringBuilder);

    }
}

在这里插入图片描述
获取String中的字段
在这里插入图片描述

反射机制操作属性

  • 赋值和获取值
  • field.set() field.get()
package com.wcy.code02;

import java.lang.reflect.Field;

/**
 * 通过反射来操作属性
 * 赋值
 * 获取值
 */
public class ReflectField02 {
    public static void main(String[] args) throws  Exception{
        Class<?> c = Class.forName("com.wcy.code02.User");
        //实例化一个对象
        Object o = c.newInstance();

        //首先获取属性 通过名称获取
        Field no = c.getDeclaredField("no");

        //设置值
        //给o对象的no属性设置值
        no.set(o, 10086);

        //获取值
        //获取o对象的no值
        System.out.println(no.get(o));

    }
}

class User {
    public int no;
    private String name;
    protected int age;
    boolean sex;
    public static final double PI = 3.1415926;
}

反射机制操作私有属性

用上面的方法还不能操作私有的属性会报错
Class com.wcy.code02.ReflectField02 can not access a member of class com.wcy.code02.User with modifiers "private"
需要设置field.setAccessible(true);才可以操作私有属性

package com.wcy.code02;

import java.lang.reflect.Field;

/**
 * 通过反射来操作属性
 * 赋值
 * 获取值
 */
public class ReflectField02 {
    public static void main(String[] args) throws  Exception{
        Class<?> c = Class.forName("com.wcy.code02.User");
        //实例化一个对象
        Object o = c.newInstance();

        //首先获取属性 通过名称获取
        Field no = c.getDeclaredField("no");
        //获取私有属性
        Field name = c.getDeclaredField("name");

        //设置值
        //给o对象的no属性设置值
        no.set(o, 10086);

        //要更改私有属性的值必须设置
        name.setAccessible(true);
        name.set(o, "wcy");

        //获取值
        //获取o对象的no值
        System.out.println(no.get(o));
        System.out.println(name.get(o));

    }
}

反射机制操作方法

获取方法相关的信息

  • 一系列get方法 见名知意 和获取属性基本一样
package com.wcy.code03;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;

/** 反射 method
 * 获取class中method的信息
 */
public class ReflectMethod01 {
    public static void main(String[] args) throws Exception{
        Class<?> c = Class.forName("com.wcy.code03.UserService");
        Method[] methods = c.getDeclaredMethods();
        //拼接字符串
        StringBuilder stringBuilder = new StringBuilder();
        for (Method method: methods){
            //获取修饰符
            String modifier = Modifier.toString(method.getModifiers());
            stringBuilder.append(modifier);
            stringBuilder.append(" ");
            //获取返回值类型
            String returnType = method.getReturnType().getSimpleName();
            stringBuilder.append(returnType);
            stringBuilder.append(" ");
            //获取方法名称
            String methodName = method.getName();
            stringBuilder.append(methodName);
            stringBuilder.append("(");
            //获取参数类型列表
            Parameter[] parameters = method.getParameters();
            for (Parameter parameter: parameters) {
                //参数类型
                String typeName = parameter.getType().getSimpleName();
                stringBuilder.append(typeName);
                stringBuilder.append(" ");
                //参数名称 获取不到真的名字 arg0 arg1...
                String name = parameter.getName();
                stringBuilder.append(name);
                stringBuilder.append(",");
            }
            //去除空格
            if(stringBuilder.charAt(stringBuilder.length()-1)==','){
                stringBuilder.deleteCharAt(stringBuilder.length()-1);
            }
            stringBuilder.append(")\n");
        }
        System.out.println(stringBuilder);

    }
}

/**
 * 模拟登陆注销功能
 */
class UserService{
    /**
     * 模拟登陆方法
     * @param name:用户名
     * @param password:密码
     * @return 是否登陆成功
     */
    public boolean login(String name, String password){
        return name.equals("wcy") && password.equals("123");
    }

    public void logout(){
        System.out.println("退出登陆成功!");
    }

}

在这里插入图片描述

反射机制调用方法

  • public Object invoke(Object obj, Object… args)
  • 获取方法后通过调用invoke来调用
package com.wcy.code03;

import java.lang.reflect.Method;

/**
 * 反射机制调用方法 !重要
 * 调用方法的四要素
 *      1.对象
 *      2.方法名
 *      3.参数
 *      4.返回值
 *  无论是普通调用还是反射机制调用都是需要的四要素
 *
 *  可变长参数补充:
 *      type... args
 *      -可变长参数
 *      -必须放在参数列表的最后
 *          public void login(int i, String... args){}
 *      - 传入多个参数会变成一个数组
 *      - 也可以直接传入一个对应类型的数组
 */
public class ReflectMethod02 {
    public static void main(String[] args) throws Exception{
        //普通调用
        UserService userService = new UserService();
        boolean isLogin = userService.login("wcy", "123");
        System.out.println(isLogin);

        //反射调用
        // 1 获取类实例对象
        Class<?> c = Class.forName("com.wcy.code03.UserService");
        Object o = c.newInstance();
        // 2 获取方法 获取的方法参数类型必须一致
        // java支持方法重载 所以方法名可能重复 需要用参数类型来限制
        Method login = c.getMethod("login", String.class, String.class);
        // 3 传参调用 获取返回值 通过invoke调用
        Object isLogin1 = login.invoke(o, "wcy", "123");
        System.out.println(isLogin1);
    }
}



/**
 * 模拟登陆注销功能
 */
class UserService{
    /**
     * 模拟登陆方法
     * @param name:用户名
     * @param password:密码
     * @return 是否登陆成功
     */
    public boolean login(String name, String password){
        return name.equals("wcy") && password.equals("123");
    }

    public void logout(){
        System.out.println("退出登陆成功!");
    }

}

在这里插入图片描述
通过反射机制,极大的降低了代码的耦合性,所有需要操作的逻辑,一次书写无需改变,只需将需要改变的部分添加到配置文件中,通过资源读取即可。

反射机制操作构造函数

获取构造方法的相关信息

  • 和前面大同小异
package com.wcy.code04;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;

/**
 * 获取构造方法
 */
public class ReflectConstructor01 {
    public static void main(String[] args) throws Exception{
        Class<?> c = Class.forName("com.wcy.code04.Student");
        Constructor<?>[] constructors = c.getDeclaredConstructors();
        for (Constructor<?> constructor: constructors){
            //修饰符
            String modifiers = Modifier.toString(constructor.getModifiers());
            System.out.println(modifiers);
            //参数列表
            Parameter[] parameters = constructor.getParameters();
            for(Parameter parameter:parameters){
                //获取类型
                String type = parameter.getType().getSimpleName();
                System.out.println(type);

            }
            System.out.println("--------------------------");
        }

    }
}

class Student{
    int no;
    String name;
    boolean sex;
    int age;

    public Student() {
    }

    public Student(int no) {
        this.no = no;
    }

    public Student(int no, String name, boolean sex) {
        this.no = no;
        this.name = name;
        this.sex = sex;
    }

    public Student(int no, String name, boolean sex, int age) {
        this.no = no;
        this.name = name;
        this.sex = sex;
        this.age = age;
    }
}

通过构造方法实例化对象

package com.wcy.code04;


import java.lang.reflect.Constructor;

/**
 * 通过构造方法来实例化对象
 * 前面实例化对象都是通过obj.newInstance()来实例化
 * 现在通过构造方法来实例化
 */
public class ReflectConstructor02 {
    public static void main(String[] args) throws Exception{
        Class<?> c = Class.forName("com.wcy.code04.Student");

        // 通过obj.newInstance()来实例化
        // 这样会默认自动调用无参构造方法来实例化一个对象
        Object o1 = c.newInstance();
        System.out.println(o1);

        //通过构造方法来实例化
        //4参数的构造方法 通过参数类型来选取
        Constructor<?> constructor1 = c.getDeclaredConstructor(int.class, String.class, boolean.class, int.class);
        //还是通过newInstance()方法实例化,参数就是需要初始化的参数
        Object o2 = constructor1.newInstance(10086, "wcy", true, 20);
        System.out.println(o2);

        //1个参数构造方法
        Constructor<?> constructor2 = c.getDeclaredConstructor(int.class);
        Object o3 = constructor2.newInstance(10000);
        System.out.println(o3);

        //无参构造
        Constructor<?> constructor3 = c.getDeclaredConstructor();
        Object o4 = constructor3.newInstance();
        System.out.println(o4);
    }
}

在这里插入图片描述

通过反射机制获取父类相关信息

package com.wcy.code04;

/**
 * 获取父类
 * 只要获取到了父类
 * 就可以用之前的方法获取属性方法等
 */
public class ReflectSuper01 {
    public static void main(String[] args) throws Exception{
        Class<?> c = Class.forName("java.lang.reflect.Method");
        //获取父类
        Class<?> superclass = c.getSuperclass();

        //名称
        String name = superclass.getName();
        System.out.println(name);

        //获取该类实现的接口
        //Class<?>[] interfaces1 = c.getInterfaces();

        //父类实现的接口
        Class<?>[] interfaces = superclass.getInterfaces();
        for (Class<?> in : interfaces) {
            String name1 = in.getName();
            System.out.println(name1);
        }
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值