• 反射学习笔记


    反射

    反射机制有什么用?

    ​ 通过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());
    

  • 相关阅读:
    Android五天乐(第三天)ListFragment与ViewPager
    Thinking in States
    红黑树上的连接操作
    [LeetCode][Java] Binary Tree Level Order Traversal
    使用IR2101半桥驱动电机的案例
    HDU 4782 Beautiful Soup(模拟)
    C语言之基本算法38—格式化输出10000以内的全部完数
    远在美国的凤姐为何选择回国理財?
    2014-7-20 谁还认得这几本书?
    360在线笔试---反思两道题
  • 原文地址:https://www.cnblogs.com/longlonglonglong/p/16177449.html
Copyright © 2020-2023  润新知