反射学习笔记

反射

反射机制有什么用?

​ 通过java语言中的反射机制可以操作字节码文件。有点类似于黑客(可以读和修改字节码文件)

​ 通过反射机制可以操作代码片段

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

​ java.lang.reflect

反射机制相关的类有哪些

​ java.lang.class //代表整个字节码,代表一个类型

​ java.lang.reflect.Method //代表字节码中的方法字节码,类中的方法

​ java.lang.reflect.Constructor //代表字节码中的构造方法字节码,类中的构造方法

​ java.lang.reflect.Field //代表字节码中的属性字节码,类中的成员变量

关于类加载器

JDK自带3个类加载器

​ 启动类加载器

​ 扩展类加载器

​ 应用类加载器

假设有这样一段代码:

String s = "abc";

代码在开始执行之前,会将所需要的类全部加载到JVM当中。通过类加载器加载,看到以上代码类加载器会找String.class文件,找到就加载

​ 首先通过启动类加载器加载

​ 注意:启动类加载器专门加载:.\jdk1.8.0\jre\lib\rt.jar中rt.jar都是JDK最核心的类库。

​ 如果通过启动类加载器加载不到时

​ 会通过扩展类加载器加载

​ 注意:扩展类加载器专门加载:.\jdk1.8.0\jre\lib\ext\*.jar

​ 如果扩展类加载器没有加载到

​ 那么会通过应用类加载器加载

​ 注意:扩展类加载器专门加载:classpath中的jar包(class文件)

java中为了保证类加载的安全,使用了双亲委派机制,父:启动类加载器,母:扩展类加载器

反射属性Field

 //获取整个类
            Class c = Class.forName("misson.reflection.net.ReflectTest04");
            //完整类名
            System.out.println("完整类名:"+c.getName());
            System.out.println("简类名:"+c.getSimpleName());
            //获取类中所有的属性名字(获取的值与权限有关)
            Field[] fields = c.getFields();
            System.out.println(fields.length);// 1

            Field[] fields1 = c.getDeclaredFields();
            System.out.println(fields1.length);// 4

            for (Field field : fields1) {
                //获取修饰符(每一个数字是一个修饰符的代号)
                int i = field.getModifiers();
                    //修饰符转换成字符串
                System.out.print(Modifier .toString(i)+": ");
                //获取类型名
                String typeName = field.getType().getSimpleName();
                System.out.print(typeName+":");
                //获取属性的名字
                System.out.println(field.getName());
            }

反编译Field

public static void main(String[] args) {
        try {
            //拼接字符串
            StringBuilder s = new StringBuilder();
            Class c = Class.forName("misson.reflection.net.ReflectTest05");

            //类名
            s.append(Modifier.toString(c.getModifiers()) +" class "+c.getSimpleName() +"{\n");

            //成员变量
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                s.append("\t");
            //每一行成员变量    
       			    s.append(Modifier.toString(field.getModifiers())+" "+field.getType().getSimpleName()+" "+field.getName()+"\n");
            }

            s.append("}");

            System.out.println(s);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

访问对象属性(重要!)

不使用反射机制(三要素:obj对象,age属性,属性值)

			ReflectTest06 reflectTest06 = new ReflectTest06();
            //给属性赋值
            reflectTest06.age = 20;
            //读取属性值
            System.out.println(reflectTest06.age);

使用反射机制(三要素:obj对象,age属性,属性值)

             // 调用无参数构造方法
            Object obj = c.newInstance();
            // 根据属性名称获取Field
            Field agefield  = c.getDeclaredField("age");
            // 给obj对象的age属性赋值
            agefield.set(obj,30);
            // 读取属性值
            System.out.println(agefield.get(obj));

是否可以访问private的?不行!

但是可以用field.setAccessible(true)打破封装,设置完后,在外部也是可以访问private的

可变长度参数

public static void m(int... args){
    
} 
//args可以做一个数组
public static void m2(int i,String... args){
    
} 
//可变长度参数要求的参数个数是0-n个
public static void main(String[] args) {
    m();
    m(10);
    m(10,20);
    
    m2(100);
    m2(100,"sa");
    m2(100,"dsa","dsa");
    m2(100,"Dsa","Dsa","dsvds");
    //也可以直接传一个数组
    m2(200,new String[]{"我","是","中","国","人"});
}

报错!

public static void m(String... args,int... args){
    //错误可变长参数只能在最后一个,只能出现一个
} 

反射属性Method

反编译Method

public class ReflectTest07 {
    public static void main(String[] args) {
        try {
            Class c = Class.forName("misson.reflection.net.UserService");
            Method[] methods = c.getDeclaredMethods();
            StringBuilder s = new StringBuilder();

            for (Method method : methods) {
                //修饰符
                s.append("方法:"+Modifier.toString(method.getModifiers()));
                //返回值名称
                s.append(" "+method.getReturnType().getSimpleName());

                //方法名
                s.append(" "+method.getName());


                //参数类型数组
                Class[] cmethods = method.getParameterTypes();
                s.append("(");
                //参数类型
                for (Class cmethod : cmethods) {
                    s.append(cmethod.getSimpleName()+",");
                }
                s.deleteCharAt(s.length()-1);
                s.append(")");
                s.append("{\n");
                s.append("}\n");
                
            }
            System.out.println(s);


        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}
class UserService{

    public String login(String userName,String passWord){
        return ";";
    }
    public void add(int i){

    }
}

调用方法(最重要的!)

 Class c = Class.forName("misson.reflection.net.UserService");
            Object obj = c.newInstance();
            //获取方法不能只用方法名
            Method loginmethod = c.getDeclaredMethod("login",new Class[]{String.class,String.class});
            //调用方法(要素:对象,方法名,实参列表,返回值)
            Object s = loginmethod.invoke(obj,"admin","124");
            System.out.println(s);

反射机制很具有通用性,让可变化的内容都是写到配置文件当中,就算对象不一样了,调用的方法不同了,但是java代码不需要做任何改变

反射属性Constructor

反编译Constructor

//拼接构造方法
        Constructor[] constructors = c.getDeclaredConstructors();
        for (Constructor constructor : constructors) {
            s.append("\t");
            s.append(Modifier.toString(constructor.getModifiers())+" ");
            s.append(c.getSimpleName());
            //参数参数
            Class[] classes = constructor.getParameterTypes();
            s.append("(");
            for (Class aClass : classes) {
                s.append(aClass.getSimpleName()+",");
            }
            if (classes.length!=0) {
                s.deleteCharAt(s.length() - 1);
            }
            s.append(")");
            s.append("{");
            s.append("}\n");
        }

调用构造方法

通过反射机制,调用构造方法实例化java对象

Class c = Class.forName("misson.reflection.net.ReflectTest09");

        //无参
        Object obj = c.newInstance();
        //有参
        Constructor constructor = c.getDeclaredConstructor(int.class,String.class,int.class,boolean.class);
        Object obj1 = constructor.newInstance(110,"jackson",150,true);
        System.out.println(obj1.toString());

posted on 2022-04-22 09:21  18软工五班龙向昆  阅读(24)  评论(0编辑  收藏  举报

导航