• 反射


    反射

    在了解反射之前需要先了解一下什么是类加载器。

    1.1 类的加载

    当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。

    加载

      就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象,同时在堆中也会创建一个文件对象(也叫字节码文件对象,可以访问文件中所有信息),具有唯一性。

    连接

      验证 是否有正确的内部结构,并和其他类协调一致

      准备 负责为类的静态成员分配内存,并设置默认初始化值

      解析 将类的二进制数据中的符号引用替换为直接引用

    初始化

    1.2 类初始化时机

    就是被加载到内存

    1. 创建类的实例

    2. 类的静态变量,或者为静态变量赋值

    3. 类的静态方法

    4. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象    这是要研究的

    5. 初始化某个类的子类

    6. 直接使用java.exe命令来运行某个主类

    验证:

     

    public class Person {
        static int a=1;
        static{
        //静态代码块验证,有且第一次使用该类进内存的时候,只执行一次 System.out.println(
    "Person类进内存了"); } }
    public class Demo01 {
        public static void main(String[] args) {
         //创建类的实例
    //new Person();
         //类的静态变量或者赋值
    //System.out.println(Person.a);
         //初始化某个子类,父类进内存 因为子类进内存,父类会被初始化
    new Zi(); } }
    public class Zi extends Person {
    
    }

     

    1.3 类加载器

     负责将.class文件加载到内存中,并为之生成对应的Class对象。

    1.4 类加载器的组成

    Bootstrap ClassLoader 根类加载器

      也被称为引导类加载器,负责Java核心类(系统内部类)的加载

      比如System,String等。在JDK中JRE的lib目录下rt.jar文件中

    Extension ClassLoader 扩展类加载器

      负责JRE的扩展目录中jar包(引入类)的加载。

      在JDK中JRE的lib目录下ext目录

    System ClassLoader 系统类加载器

      负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径。

      通过这些描述就可以知道我们常用的类,都是由谁来加载完成的。

      到目前为止我们已经知道把class文件加载到内存了,那么,如果我们仅仅站在这些class文件的角度,我们如何来使用这些class文件中的内容呢?

      这就是我们反射要研究的内容。

      研究如何获得class文件对象,并获取里面的内容

     反射

      JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

      要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象

      

    获取Class对象的三种方法

    public class Person {
        private int age;
        public String name;
        public Person(){
            System.out.println("public Person()");
        }
        private Person(String name){
            System.out.println("Person(String name)");
        }
        public void eat(){
            System.out.println("public void eat()");
        }
        private void sleep(String name){
            System.out.println("private void sleep(String name)");
        }
    }
    public class Demo01 {
        public static void main(String[] args) throws ClassNotFoundException {
            //1.通过Object中的getClass方法获取
            Person p=new Person();
            Class c=p.getClass();
            System.out.println(c);
            //2.通过class属性获取
            Class c2=Person.class;
            System.out.println(c2);
         //因为是同一个class文件对象,所以地址相同 System.out.println(c
    ==c2);
        //因为是同一个class文件对象,所以地址相同,内容也相同 System.out.println(c.equals(c2));
    //3.通过forName获取
         //JDBC加载链接数据库也用此方法
    Class c3=Class.forName("com.oracle.demo02.Person");//输入完整的包名+类名,不能只写类名 System.out.println(c3); } }

    注意:第三种和前两种的区别

      前两种你必须明确Person类型.

      后面是指定这种类型的字符串就行.这种扩展更强.我不需要知道你的类.我只提供字符串,按照配置文件加载就可以了

     通过反射获取构造方法并使用

      在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:

     返回一个构造方法

       public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法

       public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)

     返回多个构造方法

       public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法

       public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法(包含私有的)

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
            //获取字节码文件对象
            Class c=Class.forName("com.oracle.demo02.Person");
            //获取公共构造方法
            Constructor con=c.getConstructor();
            System.out.println(con);
            //创建对象  向下转型
         //通过class对象调用Instance()只能使用无参构造方法
    Person p=(Person)con.newInstance(); p.eat(); } }

      这个过程通过反射获取对象,没有通过new,也没有通过反序列化。

    什么是反射?

      反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

  • 相关阅读:
    JS调用App方法及App调用JS方法
    提升用户体验之 选用合适的鼠标光标
    js仿QQ拖拽删除
    Linux下安装 mongodb
    QQ分享-定制分享卡片
    js判断浏览器语言实现网站国际化
    js复制内容到剪切板
    为什么会有堆内存和栈内存之分
    Avro实现RPC
    zookeeper学习day01
  • 原文地址:https://www.cnblogs.com/xinzong/p/14479090.html
Copyright © 2020-2023  润新知