反射机制

反射机制

​ 通过java语言中的反射机制可以操作字节码文件。

​ 类似于黑客(可以读和修改字节码文件)

​ 通过反射机制可以操作代码片段(class文件)

反射机制的相关类在那个包下?

​ java.lang.reflect.*;

反射机制相关的重要的类有哪些

java.lang.Class: 代表整个字节码,代表一个类型,代表一个类
java.lang.reflect.Method:代表字节码中的方法字节码。
java.lang.reflect.Constructor:代表字节码中的构造方法字节码。
java.lang.reflect.Field:代表字节码中的属性字节码。

获取Class的三种方式

第一种方式:
package com.aaa.reflex;

import com.sun.media.jfxmediaimpl.HostUtils;

public class ReflectTest01 {
    public static void main(String[] args) {

        /*
        * Class.forName();   类的名称
        *       1. 静态方法
        *       2. 方法的参数是一个字符串
        *       3. 字符串需要一个完整的类名
        *       4.完整的类名包括包名。
        * */
        try {
            Class c1=Class.forName("java.lang.String"); //获取到String的字节码文件,就是String类型
            
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
第二种方式 :

​ Object类中有一个getClass()方法

String s="abc";
Class  aClass = s.getClass();
System.out.println(aClass);
第三种方式

Class z= String.class; //代表String类型

Class y=Date.class; //代表Date类型

package com.aaa.reflex;

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

/*
*
*  验证反射机制的灵活性
*       这样写代码的好处是不修改源代码,只需要修改配置文件中的配置就可以实现不同的效果。
* */
public class ReflectTest03 {

    public static void main(String[] args) throws Exception{
        FileReader fileReader = new FileReader("java-05-reflex/src/classinfo.properties");
        Properties properties=new Properties();
        //加载classinfo.properties文件
        properties.load(fileReader);
        //关闭流
        fileReader.close();
        String className = properties.getProperty("className");
        //使用反射机制来获取类的字节码文件
        Class c1=Class.forName(className);
        //使用反射机制来实例化对象
        Object o = c1.newInstance();
        System.out.println(o);
    }
}

文件路径问题

package com.aaa.reflex;

/*
*
* */
public class ReflectTest04 {
    public static void main(String[] args) {
        //获取文件的绝对路径 通用的。前提是:文件需要在类路径下
        /*
        *  Thread.currentThread():获取当前线程
        *  getContextClassLoader()是线程的方法,可以获取到当前线程的类加载器对象
        *   getResource() 获取资源 这是类加载器的方法,当前线程的类加载器默认从类的根目录(src)下加载资源
        * */
        String path = Thread.currentThread().getContextClassLoader().
                getResource("classinfo2.properties").getPath();
        System.out.println(path);
    }
}

资源绑定器

​ java.util包下提供了一个资源绑定器,便于获取属性配置文件中的内容。

使用这种方式,属性配置文件xx.properties必须放到类路径下。

//资源绑定器,只能绑定xxx.properties文件。并且这个文件必须在类路径下。文件扩展名也必须是properties
//并且在写路径的时候,路径后边的扩展名不能写。
import java.util.ResourceBundle;

public class ResourcBundTest {
    public static void main(String[] args) {
        //资源绑定器  只能绑定xxx.properties ,文件必须在类路径下
        //文件的扩展名不能写。
        ResourceBundle resourceBundle=ResourceBundle.getBundle("classinfo");

        String className = resourceBundle.getString("className");
        System.out.println(className);
    }
}

类加载器有3个分别是启动类加载器,扩展类加载器,应用类加载器。

加载顺序 :启动类加载器加载不到,在使用扩展类加载类,否则使用应用类加载器。

java中为了保证类加载的安全,使用了双亲委派机制优先从启动类加载器中加载,这个称为父

父加载不到,再从扩展类加载器中加载这个称为母。

双亲委派。如果都加载不到,才会考虑从应用加载器中加载。直到加载到为止。

获取Field

package com.aaa.reflex;

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

public class ReflectFieldTest01 {
    public static void main(String[] args) throws Exception {
        Class studentClass=Class.forName("com.aaa.bean.Student");

        //获取Field(属性)
        //getFields()方法只能获取到 公用的属性
        Field[] fields = studentClass.getFields();
        //获取到属性的访问权限修饰符,类型,全限定类名
       Field field=fields[0];
        System.out.println(field);

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

            //返回所有的属性无论是不是公有的还是私有的等
        Field[] declaredFields = studentClass.getDeclaredFields();

        for (Field declaredField : declaredFields) {
            //获取到属性的修饰符列表
            int modifiers = declaredField.getModifiers();
            //可以将这个“代号”数字转成字符串
            String string = Modifier.toString(modifiers);
            System.out.println(string);
            //获取到属性的类型
            Class  type = declaredField.getType();
            //获取到属性类型的完整名称
            //String name = type.getName();
           // System.out.println(name);
            //获取到属性类型的简单名称
            String simpleName = type.getSimpleName();
            System.out.println(simpleName);
            //获取到属性的名字
            System.out.println(declaredField.getName());
        }

    }
}

反编译Field(了解)

package com.aaa.reflex;


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

/*
*  反编译类的属性
* */
public class ReflectFieldTest02 {
    public static void main(String[] args)  throws  Exception{

        StringBuilder s=new StringBuilder();

        //获取class类对象
        Class  studentClass=Class.forName("com.aaa.bean.Student");

        s.append(Modifier.toString(studentClass.getModifiers())+" class "+studentClass.getSimpleName()+"{" +"\n");

        Field[] fields = studentClass.getDeclaredFields();
        for (Field field : fields) {

            s.append("\t");
            s.append(Modifier.toString(field.getModifiers()));
            s.append(" ");
            s.append(field.getType().getSimpleName());
            s.append(" ");
            s.append(field.getName());
            s.append(";");
            s.append("\n");

        }

        s.append("}");

        System.out.println(s);;

    }
}

通过反射机制访问对象属性(重点)

package com.aaa.reflex;


import com.aaa.bean.Student;

import java.lang.reflect.Field;

/*
*  重点:
*       怎么通过反射机制访问一个java对象的属性?
*           给属性赋值set
*           获取属性的值get
*
*
* */
public class ReflexTest05 {
    public static void main(String[] args)  throws  Exception{


        //使用反射机制获取类
        Class<Student> studentClass= (Class<Student>) Class.forName("com.aaa.bean.Student");
        //通过反射机制获取的类来实例化这个对象
        Student student = studentClass.newInstance();
        //获取no属性(根据属性名来获取到属性)
        Field no = studentClass.getDeclaredField("no");
        //给student对象的no属性赋值
        /*
        *  虽然使用了反射机制,但是三要素缺一不可。
        *   要素一:student对象
        *   要素二:no属性
        *   要素三:123值
        * */
        no.set(student,123);
        //获取到student对象中no的属性值。
        System.out.println(no.get(student));
    }
}
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true); //打破封装,可以访问不是public修饰的属性
name.set(student,"小兵");
System.out.println(name.get(student));

反射机制的缺点:打破封装,可能会给不法分子留下机会

反射Method(了解)

package com.aaa.reflex;

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

/*
*  反射方法Method
* */
public class ReflectMethodTest {

    public static void main(String[] args)  throws Exception{

        Class userServiceClass=Class.forName("com.aaa.service.UserService");


        Method[] declaredMethods = userServiceClass.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {
            //获取方法的访问修饰符
            String modifier = Modifier.toString(declaredMethod.getModifiers());
            System.out.println("方法的访问修饰符"+modifier);
            //获取方法的返回值
            Class returnType = declaredMethod.getReturnType();
            String name = returnType.getSimpleName();
            System.out.println("方法的返回值类型"+name);
            //获取方法的方法名
            String methodName = declaredMethod.getName();
            System.out.println(methodName);
            //获取方法的形式参数
           Class [] genericParameterTypes = declaredMethod.getParameterTypes();
            for (Class genericParameterType : genericParameterTypes) {

                String simpleName = genericParameterType.getSimpleName();
                System.out.println("参数列表"+simpleName);
            }
        }
    }
}

反射机制调用方法(重点,必须掌握)

package com.aaa.reflex;

import com.aaa.bean.User;
import com.aaa.service.UserService;

import java.lang.reflect.Method;

/*
*
*  使用反射机制调用方法
* */
public class ReflectMethodTest03 {
    public static void main(String[] args) throws Exception {
        //不使用反射机制怎么调用方法
        UserService userService=new UserService();
        userService.logout();
        //首先我们需要把对象给实例化出来
        Class users=Class.forName("com.aaa.service.UserService");
        Object o = users.newInstance();

        //获取方法 Method
        Method login = users.getDeclaredMethod("login", String.class, String.class);

        //调用方法
        /*
        * 调用方法 有几个要素?
        *  要素一:对象
        *  要素二:方法名
        *   要素三:实参列表
        *   要素四:返回值
        * */
        //invoke 调用
        Object invoke = login.invoke(o, "admin", "admin");

        System.out.println(invoke);


    }
}

使用属性文件来动态的调用

className=com.aaa.service.UserService
name=admin
password=admin
package com.aaa.reflex;

import java.lang.reflect.Method;
import java.util.ResourceBundle;

/*
*  反射机制调用方法
* */
public class ReflectMethodTest04 {
    public static void main(String[] args)  throws  Exception{
        //资源绑定器,只能绑定xx.properties 属性文件
        ResourceBundle resourceBundle=ResourceBundle.getBundle("classinfo");
        String className = resourceBundle.getString("className");
        Class users= Class.forName(className);

        //实例化UserService
        Object o = users.newInstance();

        //获取到方法
        //第一个参数填写方法名,第二个是可变长参数  填写形参的class类型
        Method login = users.getDeclaredMethod("login", String.class, String.class);

        //调用方法
        //login方法在o这个对像中,login方法有两个实参列表
        Object invoke = login.invoke(o, resourceBundle.getString("name"), resourceBundle.getString("password"));
        System.out.println(invoke);

    }
}
//这样写的好处是不需要修改源代码,只需要修改属性文件就可以做到动态的修改

反射Constructor

package com.aaa.reflex;

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

/*
*  反射机制之构造
*           Reflect Constructor
*
* */
public class ReflectConstructor {
    public static void main(String[] args) throws  Exception {
        Class student=Class.forName("com.aaa.bean.Student");
        //实例化对象
        Object o = student.newInstance();

        Constructor[] declaredConstructors = student.getDeclaredConstructors();
        //类中构造方法的个数
        System.out.println("构造方法的个数:"+declaredConstructors.length);

        for (Constructor declaredConstructor : declaredConstructors) {
            //获取构造方法的访问修饰符
            String modifier = Modifier.toString(declaredConstructor.getModifiers());
            System.out.println("访问修饰符:"+modifier);
            //获取构造的名称
            String name = student.getSimpleName();

            System.out.println("构造方法的方法名:"+name);
            Class[] parameterTypes = declaredConstructor.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                System.out.println("参数的类型:"+parameterType.getSimpleName());
            }
        }

    }
}

反编译Constructor(构造)

package com.aaa.reflex;

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

/*
*  反编译Constructor
*  */
public class ReflectConstructorTest03 {
    public static void main(String[] args) throws  Exception {

        Class  student=Class.forName("com.aaa.bean.Student");

        StringBuilder a=new StringBuilder();
        //访问修饰符
        String modifier = Modifier.toString(student.getModifiers());
        a.append(modifier+" class "+student.getSimpleName()+"{\n");


        //拼接中间部分
        //拼接属性
        Field[] fields = student.getDeclaredFields();

        for (Field field : fields) {

            a.append("\t");
            a.append(Modifier.toString(field.getModifiers()));

            a.append(" ");
            a.append(field.getType().getSimpleName());
            a.append(" ");
            a.append(field.getName());
            a.append(";\n");

        }
        //拼接构造方法
        Constructor[] constructor = student.getDeclaredConstructors();

        for (Constructor constructor1 : constructor) {
            a.append("\t");
            a.append(Modifier.toString(constructor1.getModifiers()));
            a.append(" ");
            a.append(student.getSimpleName());
            a.append("(");
            //拼接参数
            Class[] parameterTypes = constructor1.getParameterTypes();
            for (Class parameterType : parameterTypes) {
                a.append(parameterType.getSimpleName());

                a.append(",");


            }
            //删除最后下标位置上的字符
            if (parameterTypes.length>0) {
                a.deleteCharAt(a.length()-1);
            }
            a.append("){\n");
            a.append("\t}\n");

          }


        a.append("\n }");

        System.out.println(a);


    }
}

反射机制调用Constructor

package com.aaa.reflex;

import com.aaa.bean.Student;

import java.lang.reflect.Constructor;

/*
*   通过反射机制调用构造方法
*
* */
public class ReflectConstructorTest05 {
    public static void main(String[] args) throws  Exception {
	 Class student=Class.forName("com.aaa.bean.Student");

        Object o = student.newInstance();
        //获取到这个有参数的构造方法。
        Constructor constructor = student.getDeclaredConstructor(int.class,
                String.class, double.class, int.class);

        //调用构造方法new对象
        Object admin = constructor.newInstance(11, "admin", 10, 12);
        System.out.println(admin);


    }
}

获取父类和父接口

package com.aaa.reflex;

import java.lang.reflect.AnnotatedType;

/*
*  给你一个类如何获取这个类的父类以及这个类实现了哪些接口
*
* */
public class ReflectTest06 {
    public static void main(String[] args)  throws  Exception{
        Class  c=Class.forName("java.lang.String");
        //获取这个类的父类
        Class superclass = c.getSuperclass();
        //获取父类的类型
        System.out.println(superclass.getName());
        //获取这个类的父接口
        Class[] interfaces = c.getInterfaces();
        for (Class anInterface : interfaces) {
            System.out.println(anInterface);
        }

    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值