关于面试:新鲜出炉深入讲解java反射的底层原理这篇算讲的不错了

24次阅读

共计 10797 个字符,预计需要花费 27 分钟才能阅读完成。

反射

  1. 反射

Java 代码和 Java 文件

Java 代码根本格局
    1. Java 代码都在类内或者接口内
    2. 
        class 类名 {
            成员变量
            构造方法
            成员办法
            Annotation 注解
        }

Java 文件要求:
    1. 通常状况下一个 Java 文件对应一个 Java 类
    2. Java 文件蕴含以后 Java 代码的所有内容!!!

Java 文件和.class 字节码文件

Java 文件
    FirstJava.java
    通过编译器 javac ==> javac FirstJava.java ==> FirstJava.class

.class 字节码文件是什么???
    二进制可执行文件。.class 字节码文件中会蕴含 Java 文件的所有内容。.class 字节码文件蕴含 Java 程序的所有可执行内容 (正文不参加编译和执行)。

class 字节码文件在内存中的地位

class 字节码文件和 Java 代码关系

Class 类相干办法

Class Class.forName(String packageNameAndClassName) throws ClassNotFoundException;
    依据残缺的包名. 类名获取对应的 Class 类对象
    ClassNotFoundException 未找到指定类

Class 类对象.getClass();
    通过类对象获取以后类对象对应的 Class 类对象
    例如:Person p = new Person();  p.getClass() ==> Person 类对应 Class 对象

Class 类名.class;
    通过类名获取以后类对应属性 Class 对象
    例如: 
        Person.class ==> Person 类对应 Class 对象。
package com.qfedu.a_reflect;

/**
 * Class 类办法演示
 * 
 * @author 期年之前 ying@
 *
 */
public class GetClassObject {public static void main(String[] args) throws ClassNotFoundException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *             throws ClassNotFoundException;
         */
        Class cls1 = Class.forName("com.project.a_reflect.Person");
        
        /*
         * Class 类对象.getClass();
         */
        Person person = new Person();
        Class cls2 = person.getClass();
        
        /*
         * Class 类名.class;
         */
        Class cls3 = Person.class;
        
        /*
         
         *         不论是通过哪一种形式获取指定类的 Class 对象,都是同一个 Class 对象
         * 因为以后 Person 类在以后程序中有且只占用一次代码区空间。*/
        System.out.println("cls1 == cls2 :" + (cls1 == cls2));
        System.out.println("cls2 == cls3 :" + (cls2 == cls3));
        System.out.println("cls3 == cls1 :" + (cls3 == cls1));
    }
}

操作 Constructor 构造方法类

通过 Class 类对象获取对应类的 Constructor 构造方法类对象

Constructor[] getConstructors();
    获取以后 Class 对象对应类中所有非私有化构造方法类对象数组。Constructor[] getDeclaredConstructors();【暴力反射】获取以后 Class 对象对应类中的所有构造方法类对象数组,包含私有化构造方法。Constructor getConstructor(Class... parameterTypes);
    获取以后 Class 对象中,指定参数数据类型的构造方法。获取的构造方法为非私有化构造方法
    Class... parameterTypes 
        Class 类型不定长参数,用于束缚以后构造方法对应的数据类型。例如:
        无参数构造方法
        cls.getConstructor(); ==> Person();
        两个参数构造方法 (int, String)
        cls.getConstructor(int.class, String.class) ==> Person(int, String)
        
Constructor getDeclaredConstructor(Class... parameterTypes);【暴力反射】获取以后 Class 对象中,指定数据类型的构造方法,包含私有化构造方法
    例如:
        获取私有化 String 类型构造方法
        cls.getDeclaredConstructor(String.class) ==> private Person(String.class)

操作 Constructor 类对象创立对应类对象

Object newInstance(Object... parameters);
    通过 Constructor 类对象,执行对应的构造方法,创立对应类对象
    Object... 不定长参数,要求数据类型为 Object 类型。例如:
        Person(); 无参数构造方法
        Person p1 = (Person) constructor.newInstance();
        Person(int, java.lang.String);
        Person p2 = (Person) constructor.newInstance(10, "Java 真好学"); 
package com.qfedu.a_reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
 * 操作 Constructor 构造方法类对象
 * 
 * @author 期年之前 ying@
 *
 */
public class GetConstructorObject {public static void main(String[] args) 
            throws ClassNotFoundException, NoSuchMethodException, SecurityException, 
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *             throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 获取以后 Class 对象对应类中所有非私有化构造方法类对象数组
         */
        Constructor[] constructors = cls.getConstructors();
        for (Constructor constructor : constructors) {System.out.println(constructor);
        }
        
        System.out.println();
        
        /*
         * 2.【暴力反射】* 获取以后 Class 对象对应类中的所有构造方法类对象数组,包含私有化构造方法。*/
        Constructor[] declaredConstructors = cls.getDeclaredConstructors();
        for (Constructor constructor : declaredConstructors) {System.out.println(constructor);
        }
        
        System.out.println();
        
        /*
         * 3. 获取以后 Class 对象中,指定参数数据类型的构造方法。获取的构造方法为非私有化构造方法
         */
        Constructor constructor1 = cls.getConstructor();
        Constructor constructor2 = cls.getConstructor(int.class);
        Constructor constructor3 = cls.getConstructor(int.class, String.class);
        System.out.println(constructor1);
        System.out.println(constructor2);
        System.out.println(constructor3);
        
        /*
         * 4.【暴力反射】*    获取以后 Class 对象中,指定数据类型的构造方法,包含私有化构造方法
         */
        Constructor constructor4 = cls.getDeclaredConstructor(String.class);
        System.out.println(constructor4);
        
        System.out.println();
        /*
         * newInstance 创立类对象
         */
        Person p1 = (Person) constructor1.newInstance();
        Person p2 = (Person) constructor2.newInstance(10);
        Person p3 = (Person) constructor3.newInstance(20, "张三爱 Java");
        System.out.println(p1);
        System.out.println(p2);
        System.out.println(p3);
        
        /*
         * 给予暴力反射操作应用权限!!!* setAccessible(boolean flag);
         */
        constructor4.setAccessible(true);
        Person p4 = (Person) constructor4.newInstance("Java 高兴多");
        System.out.println(p4);
    }
}

操作 Method 成员办法类

通过 Class 类对象获取对应类的 Method 成员办法类对象

Method[] getMethods();
    通过 Class 类对象调用,获取以后类内的所有非私有化成员办法,蕴含从父类继承而来子类能够应用的非私有化办法。Method[] getDeclaredMethods();【暴力反射】通过 Class 类对象调用,获取以后类内的所有成员办法,包含私有化成员办法,然而不包含从父类继承而来的办法。Method getMethod(String methodName, Class... parameterTypes);
    通过 Class 类对象调用,依据办法名称和对应的形式参数列表数据类型获取对应的成员办法,能够获取父类继承办法,不能获取私有化成员办法
    例如:
        无参数成员办法 获取 game();
            cls.getMethod("game");
        有参数成员办法 获取 game(String);
            cls.getMethod("game", String.class);
    
Method getDeclaredMethod(String methodName, Class... parameterTypes);
    通过 Class 类对象调用,依据办法名称和对应的形式参数列表数据类型获取对应的成员办法,能够获取私有化成员办法,不能获取父类成员办法。例如:
        无参数私有化成员办法 testPrivate();
            cls.getDeclaredMethod("testPrivate");
        有参数私有化成员办法 testPrivate(String);
            cls.getDeclaredMethod("testPrivate", String.class);

操作 Method 类对象执行办法

Object invoke(Object obj, Object... parameters);
    通过 Method 类对象调用,执行对应办法。Object obj 执行以后办法的类对象。Object... parameters 对应以后办法的理论参数列表
package com.qfedu.a_reflect;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 操作 Method 类对象
 * 
 * @author 期年之前 ying@
 *
 */
public class GetMethodObject {public static void main(String[] args) 
            throws ClassNotFoundException, SecurityException, NoSuchMethodException, 
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *             throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 通过 Class 类对象调用,获取以后类内的所有非私有化成员办法,* 蕴含从父类继承而来子类能够应用的非私有化办法。*/
        Method[] methods = cls.getMethods();
        for (Method method : methods) {System.out.println(method);
        }
        
        System.out.println();

        /*
         * 2. 获取以后类自有成员办法,包含私有化办法,然而不蕴含父类继承给子类的办法
         */
        Method[] declaredMethods = cls.getDeclaredMethods();
        for (Method method : declaredMethods) {System.out.println(method);
        }
        System.out.println();
        
        /*
         *  3. 依据指定办法名字和参数类型,获取非私有化成员办法
         */
        Method game1 = cls.getMethod("game");
        Method game2 = cls.getMethod("game", String.class);
        
        System.out.println(game1);
        System.out.println(game2);
        System.out.println();
        
        /*
         * 4. 依据指定的办法名称和参数类型,获取私有化成员办法
         */
        Method testPrivate1 = cls.getDeclaredMethod("testPrivate");
        Method testPrivate2 = cls.getDeclaredMethod("testPrivate", String.class);
        System.out.println(testPrivate1);
        System.out.println(testPrivate2);
        System.out.println();
        
        /*
         * 调用办法
         */
        Object object = cls.getConstructor().newInstance();
        game1.invoke(object);
        game2.invoke(object, "World Of Tank");
        
        /*
         * 给予暴力反射操作权限
         */
        testPrivate1.setAccessible(true);
        testPrivate2.setAccessible(true);
        testPrivate1.invoke(object);
        testPrivate2.invoke(object, "西红柿 + 黄瓜 + 鸡蛋 + 羊肉串");
    }
}

操作 Field 成员变量类

通过 Class 类对象获取对应类的 Field 成员变量类对象

Field[] getFields();
    获取类内所有非私有化成员变量数组
    
Field[] getDeclaredFields();【暴力反射】获取类内所有成员变量数组,包含私有化成员变量
Field getField(String fieldName);
    依据成员变量名字获取对应的成员变量对象,要求以后成员变量非私有化
    例如:    
        public int test;
        cls.getField("test");

Field getDeclaredField(String fieldName);【暴力反射】获取类内指定名字的成员变量对象,包含私有化成员变量
    例如:
        private String name;
        private int id;
        cls.getDeclaredField("name");
        cls.getDeclaredField("id");        

操作 Field 类对象赋值取值成员变量

Field[] getFields();
    获取类内所有非私有化成员变量数组
    
Field[] getDeclaredFields();【暴力反射】获取类内所有成员变量数组,包含私有化成员变量
Field getField(String fieldName);
    依据成员变量名字获取对应的成员变量对象,要求以后成员变量非私有化
    例如:    
        public int test;
        cls.getField("test");

Field getDeclaredField(String fieldName);【暴力反射】获取类内指定名字的成员变量对象,包含私有化成员变量
    例如:
        private String name;
        private int id;
        cls.getDeclaredField("name");
        cls.getDeclaredField("id");        

package com.qfedu.a_reflect;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

/**
 * 操作 Field 类对象
 * 
 * @author 期年之前 ying@
 *
 */
public class GetFieldObject {public static void main(String[] args) 
            throws ClassNotFoundException, NoSuchFieldException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, 
            InvocationTargetException, NoSuchMethodException {
        /*
         * Class Class.forName(String packageNameAndClassName) 
         *             throws ClassNotFoundException;
         */
        Class cls = Class.forName("com.project.a_reflect.Person");
        
        /*
         * 1. 获取类内所有非私有化成员变量数组
         */
        Field[] fields = cls.getFields();
        for (Field field : fields) {System.out.println(field);
        }
        System.out.println();
        
        /*
         * 2. 获取类内所有成员变量数组,包含私有化成员变量
         */
        Field[] declaredFields = cls.getDeclaredFields();
        for (Field field : declaredFields) {System.out.println(field);
        }
        System.out.println();
        
        /*
         * 3. 依据成员变量名字获取对应的成员变量对象,要求以后成员变量非私有化
         */
        Field test = cls.getField("test");
        System.out.println(test);
        System.out.println();
        
        /*
         * 4. 获取类内指定名字的成员变量对象,包含私有化成员变量
         */
        Field id = cls.getDeclaredField("id");
        Field name = cls.getDeclaredField("name");
        System.out.println(id);
        System.out.println(name);    
        System.out.println();
        
        /*
         * 取值赋值成员变量
         */
        Object obj = cls.getConstructor().newInstance();
        System.out.println(obj);
        test.set(obj, 100);
        System.out.println(obj);
        System.out.println(test.get(obj));
        
        id.setAccessible(true);
        name.setAccessible(true);
        
        id.set(obj, 10);
        name.set(obj, "大哥好英武");
        System.out.println(obj);
        System.out.println(id.get(obj));
        System.out.println(name.get(obj));
        
        System.out.println();
        System.out.println(id.getType());
        System.out.println(name.getType());
    }
}

暴力反射受权

class AccessibleObject 类内办法
public static void setAccessible(AccessibleObject[] array, boolean flag);
    通过类名调用的动态工具形式,给予 AccessibleObject 类对象或者其子类对象数组,赋值操作权限。子类对象包含:Field Method Constructor
    
public void setAccessible(boolean flag);
    通过 AccessibleObject 类对象调用,繁多权限受权,Field Method Constructor 都能够应用。

案例操作

 须要应用
    1. String 办法
    2. IO 流 举荐字符流操作
    3. 反射
    4. 自行理解 ==> String 转其余类型办法 百度 parse 系列办法
 文件名:
    studentInfo.txt
文件内容:
className=com.qfedu.a_reflect.Student
name= 李四
age=18
gender=false
javaScore=59
webScore=59
dbScore=59

指标
    文件内容转 Student 类对象
package com.qfedu.a_reflect;

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;

@SuppressWarnings("all")
public class ReflectDemo {public static void main(String[] args) 
            throws IOException, ClassNotFoundException, InstantiationException, 
            IllegalAccessException, IllegalArgumentException, InvocationTargetException,
            NoSuchMethodException, SecurityException, NoSuchFieldException {
        // 1. 创立缓冲字符输出流 解决 文件
        BufferedReader br = new BufferedReader(new FileReader("./data/studentInfo.txt"));
        
        // 2. 读取文件数据
        String classInfo = br.readLine();
        String className = classInfo.substring(classInfo.indexOf("=") + 1);
        
        // 3. 启动万恶之源 获取 Class 对象,加载指定类
        Class cls = Class.forName(className);
        
        // 4. 创立对应类对象
        Object obj = cls.getConstructor().newInstance();
        
        // 5. 读取文件,利用循环操作
        String info = null;
        Object value = null;
        
        // 每一次从文件中读取一行数据
        while ((info = br.readLine()) != null) {
            // 依照 = 宰割信息 name= 李四
            String[] split = info.split("=");
            System.out.println(Arrays.toString(split));
            // 依据信息获取对应成员变量对象
            Field field = cls.getDeclaredField(split[0]);
            field.setAccessible(true);
            
            // 获取成员变量数据类型
            Class type = field.getType();
            
            // 以后成员变量数据为 String 类型
            if (type.equals(String.class)) {value = split[1];
                // field.set(obj, split[1]);
            // 成员变量数据类型为 int 类型
            } else if (type.equals(int.class)) {value = Integer.parseInt(split[1]);
            // 成员变量数据类型为 boolean 类型
            } else if (type.equals(boolean.class)) {value = Boolean.parseBoolean(split[1]);
            }
            
            field.set(obj, value);
        }
        
        System.out.println(obj);
        
        // 敞开资源
        br.close();}
}

最初

欢送关注公众号:前程有光,支付一线大厂 Java 面试题总结 + 各知识点学习思维导 + 一份 300 页 pdf 文档的 Java 外围知识点总结!这些材料的内容都是面试时面试官必问的知识点,篇章包含了很多知识点,其中包含了有基础知识、Java 汇合、JVM、多线程并发、spring 原理、微服务、Netty 与 RPC、Kafka、日记、设计模式、Java 算法、数据库、Zookeeper、分布式缓存、数据结构等等。

正文完
 0