JAVA中reflect反射的使用

反射基本概念

反射主要是指程序可以访问、检测和修改它本身状态或行为的一种能力, 并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。Java 中,反射是一种强大的工具。它使您能够创建灵活的代码,这些代码可以在运行时装配,无需在组件之间进行源代码链接。反射允许我们在编写与执行时,使我们的程序代码能够接入装载到 JVM 中的类的内部信息,而不是源代码中选定的类协作的代码。这使反射成为构建灵活的应用的主要工具。但需注意的是:如果使用不当,反射的成本很高。

java中的类反射

通过java语言中的反射机制可以操作字节码文件(.class文件)
反射机制的相关类在java.lang.reflect.*;包下
反射机制相关的重要的类:

  • java.lang.Class:代表整个字节码,代表一个类型,代表整个类。
  • java.lang.reflect.Method:代表字节码中的方法字节码。代表类中的方法。
  • java.lang.reflect.Constructor:代表字节码中的构造方法字节码。代表类中的构造方法
  • java.lang.reflect.Field:代表字节码中的属性字节码。代表类中的成员变量(静态变量+实例变量)。

获取Class对象

要操作一个类的字节码,首先需要获取到这个类的字节码,也就是Class对象,获取Class对象有三种方式

  1. 通过类路径获取

Class.forName()

  1. 这是一个静态方法
  2. 方法的参数是一个字符串
  3. 字符串需要的是一个完整的类名
  4. 完整类名必须带有包名
public class Reflect01 {
    public static void main(String[] args) {
        Class clazz= null;
        try {
            clazz = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        System.out.println(clazz);
    }
}
  1. java中的任何一个对象都有一个getClass()方法,Object类中,反射获得的就是它对应类型的字节码文件
public class Reflect02 {
    public static void main(String[] args) {
        String i="reflection";
        Class a=i.getClass();
        System.out.println(a);
    }
}
  1. 通过类来获取Class对象
public class Reflect03 {
    public static void main(String[] args) {
        Class stringClass=String.class;
        System.out.println(stringClass);
    }
}

最后注意:字节码文件装载到JVM中,只装载一份;下面的例子就说明了a和stringClass指向的是同一个地址。

public class Reflect04 {
    public static void main(String[] args) {
        String i="reflection";
        Class a=i.getClass();
        Class stringClass=String.class;
        System.out.println(a==stringClass);
    }
}

结果:
在这里插入图片描述

通过反射获取Class,通过Class来实例对象

先获得Class对象,通过Class对象的newInstance()来实例化对象,而newInstance()底层实际是调用Class对象的无参构造方法,所以说当一个类没有无参构造方法时会报错实例化异常:java.lang.NoSuchMethodException(无法初始化实例)

public class Reflect01 {
    public static void main(String[] args) {
        try {
            Class c =Class.forName("com.hyg.MyTest");
            MyTest myTest= (MyTest) c.newInstance();
            System.out.println(myTest);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        }
    }
}

结果
在这里插入图片描述

反射获取属性Field

StudentBean:分别采用不同的访问控制权限修饰符
Field: public int no; 这一整个部分 就是一个Field对象

public class StudentBean {
    public int no;
    private String name;
    protected int age;
    boolean sex;
}

从下面的演示可以看出clazz.getFields()这个方法时获取类中所有的public修饰的field

public class Reflect02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类
        Class clazz=Class.forName("com.hyg.reflection.StudentBean");
        //获取field
        Field[] fields = clazz.getFields();
        System.out.println(fields.length);
        Field field = fields[0];
        String fieldName=field.getName();
        System.out.println(fieldName);
    }
}

结果
在这里插入图片描述

下面的演示可以得知clazz.getDeclaredFields()方法可以得到类中所有的field,不管权限修饰符是什么,都可以获取到

public class Reflect02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类
        Class clazz=Class.forName("com.hyg.reflection.StudentBean");
        Field[] declaredFields = clazz.getDeclaredFields();
        System.out.println(declaredFields.length);
        for (Field f:declaredFields) {
            System.out.println(f.getName());
        }
    }
}

结果
在这里插入图片描述
获取Field中的可使用信息

public class Reflect02 {
    public static void main(String[] args) throws ClassNotFoundException {
        //获取类
        Class clazz=Class.forName("com.hyg.reflection.StudentBean");
        String name = clazz.getName();
        System.out.println("类的路径名:"+name);
        String simpleName = clazz.getSimpleName();
        System.out.println("类的简单名字:"+simpleName);
        Field[] declaredFields = clazz.getDeclaredFields();
        System.out.println("属性的个数:"+declaredFields.length);
        for (Field f:declaredFields) {
            //获取属性修饰符getModifiers 表示属性可能有多个修饰符 
            int modifiers = f.getModifiers();//返回的是一个数字,每个数字是修饰符的代号
            //将代号数字转换成字符串
            System.out.println("属性的修饰符:"+Modifier.toString(modifiers));
            //获取属性的类型
            Class<?> type = f.getType();
            System.out.println("属性的类型:"+type.getName());
            //获取属性名
            System.out.println("属性名:"+f.getName());

            System.out.println(Modifier.toString(modifiers)+" "+type.getName()+" "+f.getName());
        }
    }
}

结果
在这里插入图片描述
反编译Class和里面的属性

public class Reflect03 {
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder bean=new StringBuilder();

        Class studentBean=Class.forName("com.hyg.reflection.StudentBean");
        bean.append(Modifier.toString(studentBean.getModifiers())+" class "+studentBean.getSimpleName()+" {\n");
        Field[] declaredFields = studentBean.getDeclaredFields();
        for (Field f:declaredFields) {
            bean.append("\t");
            bean.append(Modifier.toString(f.getModifiers())+" "+f.getType().getSimpleName()+" "+f.getName()+";\n" );
        }
        bean.append("}");
        System.out.println(bean.toString());
    }
}

结果
在这里插入图片描述
通过反射机制访问一个对象的属性,给属性赋值set,获取属性的值 get

public class reflect04 {
    public static void main(String[] args) throws Exception {
        Class studentClass=Class.forName("com.hyg.reflection.StudentBean");
        //创建对象
        Object o = studentClass.newInstance();
        //获取指定属性名的Field
        Field no = studentClass.getDeclaredField("no");
        //给o 对象的no 属性赋值
        no.set(o,2020);
        //获取 o 对象的 no 值
        System.out.println( no.get(o));
        //获取私有属性
        Field name = studentClass.getDeclaredField("name");
        //上面这种方式只能访问public修饰的属性,private修饰的属性不能通过这种方式访问
        //强制访问  打破封装 
        name.setAccessible(true);
        name.set(o,"reflect");
        System.out.println(name.get(o));
    }
}

结果
在这里插入图片描述

反射获取Method

public class UserLogin {

    public boolean login(String name,String password){
        if ("admin".equals(name)&&"123".equals(password)){
            return true;
        }
        return false;
    }
    public void loginOut(){
        System.out.println("退出");
    }
}
public class Reflect05 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class userLogin=Class.forName("com.hyg.reflection.UserLogin");
        //获取所有的方法,包括私有的
        Method[] declaredMethods = userLogin.getDeclaredMethods();
        System.out.println(declaredMethods.length);
        for (Method method:declaredMethods) {
            //获取修饰符列表
            System.out.println("修饰符列表:"+ Modifier.toString(method.getModifiers()));
            //获取方法返回值类型
            System.out.println("方法放回值类型:"+method.getReturnType().getSimpleName());
            //获取方法名
            System.out.println("方法名:"+method.getName());
            //获取参数类型
            Class<?>[] parameterTypes = method.getParameterTypes();
            for (Class clazz:parameterTypes) {
                System.out.println("参数类型:"+clazz.getSimpleName());
            }
        }
    }
}

结果
在这里插入图片描述
反编译类和其中方法

public class Reflect06 {
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder a=new StringBuilder();
        Class userLogin=Class.forName("com.hyg.reflection.UserLogin");
        a.append(Modifier.toString(userLogin.getModifiers())+" class "+userLogin.getSimpleName()+" {\n");
        Method[] declaredMethods = userLogin.getDeclaredMethods();
        for (Method m:declaredMethods) {
            a.append("\t");
            a.append(Modifier.toString(m.getModifiers())+" "+m.getReturnType().getSimpleName()+" "+ m.getName()+"(");
            Class<?>[] parameterTypes = m.getParameterTypes();
            for (Class c:parameterTypes) {
                a.append(c.getSimpleName()+",");
            }
            a.deleteCharAt(a.length()-1);
            a.append("){\n");
            a.append("}\n");
        }
        a.append("}");
        System.out.println(a.toString());

    }
}

结果
在这里插入图片描述
通过反射机制调用一个对象的方法
调用方法的要素

  1. 对象
  2. 方法名
  3. 形参列表
  4. 返回值
public class Reflect07 {
    public static void main(String[] args) throws Exception {
        Class userLogin=Class.forName("com.hyg.reflection.UserLogin");
        Object o = userLogin.newInstance();
        //获取方法  由于重载的存在,获取一个方法时需要方法名 加参数列表
        Method login= userLogin.getDeclaredMethod("login", String.class, String.class);
        //调用方法
        Object value = login.invoke(o, "admin", "123");
        System.out.println(value);
    }
}

结果
在这里插入图片描述

反编译一个类的Constructor构造方法

public class StudentInfo {
   private int no;
   private String name;

    public StudentInfo() {
    }

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

    public StudentInfo(int no, String name) {
        this.no = no;
        this.name = name;
    }
        @Override
    public String toString() {
        return "StudentInfo{" +
                "no=" + no +
                ", name='" + name + '\'' +
                '}';
    }
}
public class Reflect08 {
    public static void main(String[] args) throws ClassNotFoundException {
        StringBuilder a=new StringBuilder();
        Class studentInfo=Class.forName("com.hyg.reflection.StudentInfo");
        a.append(Modifier.toString(studentInfo.getModifiers())+" class "+studentInfo.getSimpleName()+" {\n");
        Constructor[] declaredConstructors =studentInfo.getDeclaredConstructors();
        for (Constructor c:declaredConstructors) {
            a.append("\t");
            a.append(Modifier.toString(c.getModifiers())+" "+studentInfo.getSimpleName()+"(");
            Class[] clazz=c.getParameterTypes();
            for (Class i:clazz) {
                a.append(i.getSimpleName()+",");
            }
            if (clazz.length>0) {
                a.deleteCharAt(a.length() - 1);
            }
            a.append("){\n");
            a.append("}\n");
        }
        a.append("}");
        System.out.println(a.toString());
    }
}

结果

在这里插入图片描述利用反射机制使用构造方法创建对象

public class Reflect09 {
    public static void main(String[] args) throws Exception {
        Class studentInfo=Class.forName("com.hyg.reflection.StudentInfo");
        //无参构造方法创建对象
        Object o = studentInfo.newInstance();
        //有参 构造方法创建对象
        //先获取有参构造方法   感觉参数列表
        Constructor declaredConstructor = studentInfo.getDeclaredConstructor(int.class);
        Constructor constructor=studentInfo.getDeclaredConstructor(int.class,String.class);
        //调用有参构造方法new 对象
        Object o1 = declaredConstructor.newInstance(10);
        Object constructor1 = constructor.newInstance(100, "constructor");
        System.out.println(o1);
        System.out.println(constructor1);
    }
}

结果
在这里插入图片描述

获取类的父类 和实现的接口

public class Reflect10 {
    public static void main(String[] args) throws ClassNotFoundException {
        Class clazz=Class.forName("java.lang.String");
        //获取父类
        Class superclass = clazz.getSuperclass();
        System.out.println("父类:"+superclass.getName());
        //获取 实现的接口  一个类可以实现多个接口
        Class[] interfaces = clazz.getInterfaces();
        for (Class i:interfaces) {
            System.out.println("实现的接口:"+i.getName());
        }
    }
}

结果
在这里插入图片描述
在这里插入图片描述

安全性和反射

在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,我们可
能希望框架能够全面介入代码,无需考虑常规的介入限制。但是,在其它情况下,不受控制的
介入会带来严重的安全性风险,例如当代码在不值得信任的代码共享的环境中运行时。

反射的两个缺点

反射是一种强大的工具,但也存在一些不足。

  • 性能问题。使用反射基本上是一种解释操作,我们可以告诉 JVM,我们希望做什么并
    且它满足我们的要求。用于字段和方法接入时反射要远慢于直接代码。性能问题的程
    度取决于程序中是如何使用反射的。如果它作为程序运行中相对很少涉及的部分,缓
    慢的性能将不会是一个问题。
  • 使用反射会模糊程序内部实际要发生的事情。程序人员希望在源代码中看到程序的逻
    辑,反射等绕过了源代码的技术会带来维护问题。反射代码比相应的直接代码更复杂。
    解决这些问题的最佳方案是保守地使用反射——仅在它可以真正增加灵活性的地方
    ——记录其在目标类中的使用。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值