反射

Java类加载器 除了根类加载器之外,其他类加载器都是用Java语言书写的.

Java.lang.reflect 包下的借口和类:

                                                    Class(类)    Method(方法)  Filed(成员变量)    Constructor(构造器)  Array(数组)

Type(Class实现的接口)    ParameteriaedType  (带泛型参数的类型)

Proxy        InvocationHandler  (创建JDK动态代理和AOP之间的内在关系)


1.1.JVM 和 类

    JVM进程结束:

                            1.程序正常结束

                            2.运行到使用System.exit()或者Runtime.getRuntime().exit()代码处结束程序.

                            3.遇到未捕获的异常或错误结束.

                            4.强制结束JVM进程.

1.2当程序主动使用某个类时,如果该类还未被加到内存中,则系统会通过,加载,连接,初始化三个操作进行初始化.

类加载:将类的class文件读入到内存,并为之创建一个Java.lang.Class对象.====当程序使用任何类时候,系统都会为之建立一个java.lang.Class对象.

系统中所有的类实际上也是实例, 他们都是java.lang Class 的实例.

1.3类的加载由类加载器完成,类加载器通常由JVM提供 JVM提供的这些类加载器 通常被称为系统类加载器,

开发者可以通过继承ClasssLoader 基类来创建自己的类加载器.

1.4有不同的来源加载类的二进制数据:

    1.从本地系统

    2.JAR包加载class文件

    3.网络

    4.把一个Java源文件动态编译,并执行.

1.5类加载器通常无需等到“”首次使用“”该类才加载该类,Java虚拟机规范允许系统余下你贾安琪加载一些类.

1.6    类的连接:

        当类被加载后,系统为之生成一个Class对象, 接着将会进入连接阶段,连接状态负责吧类的二进制数据合并到JRE中.

        类的连接:

                        1. 验证:是否有正确的内部结构

                        2. 准备:为类的类变量分配内存,设置默认值

                        3. 解析 :  将类的二进制数据中符号引用替换成直接引用.


   1.7  类的初始化: 

虚拟机负责对类进行初始化, 主要是对类变量进行初始化,在Java类中, 对类变量指定初始值有两种方式:

        1.声明变量时候指定初始值

        2.使用静态初始化快为类变量指定初始值.

JVM初始化步骤:

            1. 程序先加载并连接该类

            2. 先初始化其直接父类

            3. 依次执行这些初始化语句.

            类初始化的时机:

                                 1 . 创建类的实例 (使用new操作符来创建实例)(通过反射来创建实例)(通过反序列的方法)

                                 2.  调用某个类的类方法(静态方法)

                                 3.  访问某个类或接口的类变量,或者为该类变量赋值

                                 4.   使用反射方式来强制创建某个类或接口对应的 java.lang.Class 对象.(Class.forName("Person"),如果系统还未初始化Person类,则这行代码会导致Person类被初始化 ,并返回Person类对应的  java.lang.Class 对象.)

                                 5.  初始化某个类的子类

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

2.不会初始化情况

    1.对于一个final型的类变量, 如果该类变量在编译时候就可以确定下来,那么这个类变量相当于“”宏变量“”.Java 编译器会在编译时直接把这个类变量出现的地方替换成它的值,因此即使程序使用该静态类变量,也不会导致该类的初始化.

    2.使用ClassLoader 类的loadClass()v方法来加载某个类时候。

3. 使用Class 的forName( )静态方法才会导致强制初始化该类.


类加载器:

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

类加载器加载所有的类,系统会为之分配唯一的标识.

            Java中 一个类用其全限定类名(包名和类名)作为标识;

            JVM 中一个类用其全限定类名和类加载器作为全限定类名.    例如: 类名  包名  实例名

java类加载器就是在运行时候JVM中动态加载所需要的类.

    -----------Java类加载器三个机制:

                            1. 委托:

                            2. 可见

                            3. 单一

把classpath下的那些.class文件加载进内存 , 处理后称为字节码 , 这些工作是类加载器做的.


  • 委托机制指的是将加载类的请求传递给父加载器,如果父加载器找不到或者不能加载这个类,那么再加载他。
  • 可见性机制指的是父加载器加载的类都能被子加载器看见,但是子加载器加载的类父加载器是看不见的。
  • 单一性机制指的是一个类只能被同一种加载器加载一次。
  • 首先当前线程的类加载器去加载线程中的第一个类
  • 如果类A应用了类B,java虚拟机将使用加载类A的类加载器来加载类B
  • 还可以直接调用ClassLoader.loadClass()方法来制定某个类加载器去加载某个类

-----------------自定义类加载器原理:

模板方法设计模式

父类:

  • loadClass(类加载的流程,模板)
  • findClass供子类覆盖的、被loadClass方法调用的类加载逻辑
  • defineClass得到class文件转换成字节码

子类:覆盖findClass方法



当JVM启动时:会形成三个类加载器组成的初始类加载器层次结构.

            1. Bootstrap  ClassLoader:  根类加载器        (加载Java的核心类,他并不是Java.lang.ClassLoader的子类,而是由JVM自身实现的)

            2. Extension  ClassLoader:扩展类加载器       (加载JRE的扩展目录(%JAVA_HOME%/jre/lib/ext或者由java.ext,dirs 系统属性指定的目录中的JAR包的类) 就可以为Java扩展核心类以外的新功能,只要把自己开发的类打包成JAR  文件,放入JAVA_HOME/jre/lib/ext  路径即可)

            3. System   ClassLoader    : 系统类加载器      (应用类加载器  负责加载来自Java命令的-classpath选项  通过 ClassLoader.getSystemClassLoader() 来获取系统类加载器.)


JVM 的类加载机制有三种:

                    1. 全盘负责:当一个类加载器负责加载某个Class时,该Class 所依赖的和引用的其他Class 也将有该类加载器 负责载入,除非显示使用另外一个类加载器来载入.

                    2. 父类委托  : 先让Parent类加载该Class 

                    3. 缓存机制  : 保证所有加载过得Class都会被缓存.当程序需要某个Class时类加载器加载器先从缓存区查找该Class,只有当找不到时候,才会读取该类对应的二进制数据,并转换成Class对象.


通过反射查看类信息:

                在Java程序中获得Class对象通常有如下三种方式:

                    1.Class.forName()静态方法

                    2.类名.class

                    3.getClass()

第一种第二种都是直接根据类来取得该类的Class对象:

第二种优势:(1)代码更安全(在编译阶段就可以检查Class对象是否存在),(2) 程序性能更好(无需调用方法)

如果程序只能获得一个字符串,例如 "java.lang.String",只能使用第一种方式,使用forName()会抛异常.



Java8 在java.lang.reflect 包下新增一个 Executable抽象基类,派生出Constructor   Method两个子类.

isModifiers() 方法来获取该方法或构造器的修饰符,

提供了两个方法获取该方法或参数的形参个数及形参名。

int  getParameterCount(); 获取该构造器或方法的形参个数

                    edg: Method clazz = Test.class;   //获取String 的类

                            Method  replace =clazz.getMethod("replace",String.class,List.class); // 获取指定方法的参数个数

                              System.out.println("replace方法参数个数"+replace.getParameterCount());

Parameter[] getParameters();  获取该构造器或方法的形参个数。

                    Parameter []  parameter = replace.getParameteres();


Class 对象 获得该类的方法(Method) 构造器(Constructor) 成员变量(Filed) 这三个类都位于java.lang.reflect 包下

--------------创建对象

1. 使用Class对象的newInstance()  方法来创建该Class对象对应类的实例,(有默认构造器)

2. 先获取指定Constructor对象。在调用Constructor对象的newInstance()方法

如果不想利用默认的构造器来创建Java对象,而利用指定的构造器来创建Java对象,则需要利用Constructor 对象.

    1.获取该类的Class对象

    2.利用Class对象的getConstructor() 方法来获取指定的构造器.

    3.调用Constructor 的newInstance() 方法来创建java 对象.



--------------调用方法

    当获得某个类对应的Class对象后, 就可以通过该对象的 getMethods() 方法 或者getMethod()方法来获取全部方法

或者指定方法 .Method 里面包含一个invoke() 方法.


---------------访问成员变量

通过Class对象的getFields() 或getField() 方法

----------------使用反射生成JDK动态代理

在java.lang.reflect 包下提供了一个Proxy 类 和一个 InvocationHandler 接口.


--------------------反射和泛型

Class类增加了泛型功能,允许使用泛型来限制Class类.




            


        









                                    












   

你可能感兴趣的:(反射)