注解和反射

注解

作用:

         不是程序本身,可以对程序作出解释;可以被其他程序读取。

格式:

         注解时以"@注释名"在代码中存在的,还可以添加一些参数值;

位置:

         可以附加在package,class,method,field等上面,相当于给他们添加了额外的辅助信息,可以通过反射机制编程实现对这些数据的访问。

常见内置注解:

     @Override:定义在java.lang.Override中,此注释只适用于修辞方法,表示一个方法声明打算重新超类中的一个方法声明。
     @Deprecated:定义在java.lang.DePrecated中,此注释可以用于修辞方法,属性,类,表示不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。
     @SuppressWarnings:定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。(需要添加一个定义好的参数才能使用)

元注解

作用:

       负责注解其他注解,java定义了4个标准的meta-annotation类型,被用来提供对其他注解类型作说明。

       @Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
       @Retention:表示需要在什么级别保存该注解信息,用于描述注解的生命周期(SOURCE<CLASS<RUNTIME)
       @Document:说明该注解将被包含在javadoc中
       @Inherited:说明子类可以继承父类中的该注解

自定义注解:

       使用@interface自定义注解时,自动继承了java.lang.annotaion.Annotation接口

分析:

       @interface用来声明一个注解,格式:@ interface 注解名{ 定义内容 }
       其中内容的每一个方法实际上是声明了一个配置参数。
       方法的名称就是参数的名称。
       返回值类型就是参数的类型(返回值只能是基本类型,Class,String,enum)。
       可以通过default来声明参数的默认值
       如果只有一个参数成员,一般参数名为value
       注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0作为默认值。

动态语言

      是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。

静态语言

      与动态语言相对应,运行时结构不可变的语言就是静态语言。

反射

       JAVA反射机制实在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
       要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法,所以先要获取到每一个字节码文件对应的Class类型的对象。

反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。首先必须得到class文件对象,既得到Class类的对象。

Class类:

            成员变量    Field
            构造方法    Constructor
            成员方法    Method
            获得私有:getDeclaredXxx..

获取class文件对象的方式:

A:Object类的getClass()方法
B:数据类型的静态属性class
C:Class类中的静态方法(参数为类的全路径(带包名))
                 public static Class<?> forName(String className)
D:基本内置类型的包装类都有一个Type属性

只要元素类型与维度都一样,就是同一个Class

Class对象作用:

创建类的对象:
调用Class对象的newInstance()方法
       类必须有一个无参的构造方法
       类的构造方法的访问权限需要足够
  若没有无参构造:
       通过Class类的getDeclaredConstructor(Class..parameterTypes)取得本类的指定形参类型的构造方法
       像构造方法的形参中传递一个对象数组进去,里面包含了构造方法中所需要的各个参数。
       通过Constructor实例化对象

调用指定的方法
       通过反射,调用类中的方法,通过Method类完成
       通过Class类的getMethod(String name, Class...parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型
       之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

Object invoke(Object obj, Object... args)
       Object对应原方法的返回值,若原方法无返回值,此时返回null
       若原方法若为静态方法,此时形参Object obj可为null
       若原方法声明为private,则需要在调用此invoke()方法前,显式调用方法对象的setAccessible(true)方法,将可访问private的方法。 

setAccessible
       Method和Field、Constructor对象都有setAccessible()方法。
       setAccessible作用是启动和禁用访问安全检查的开关。
       参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
              提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被调用,那么请设置为true.
              使得原本无法访问的私有成员也可以访问
       参数值为false则指示反射的对象应该实施Java语言访问检查

反射操作泛型

       Java采用泛型擦除的机制来引入泛型,Java中的泛型仅仅是给编译器javac使用的,确保数据的安全性和免去强制类型转换问题,但是一旦编译完成,所有和泛型有关的类型全部擦除
       为了通过反射操作这些类型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType继承几种类型来代表不能被归一到Class类中的类型但是又和原始类型齐名的类型。
       ParameterizedType:表示一种参数化类型,比如Collection<String>
       GenericArrayType:表示一种元素类型是参数化类型或者类型变量的数组类型
       TypeVariable:是各种类型变量的公共父接口
       WildcardType:代表一种通配符类型表达式

Java内存分析:

     堆:存放new的对象和数组;可以被所有的线程共享,不会存放别的对象应用
     栈:存放基本变量类型(会包含这个基本类型的具体数值);引用对象的变量(会存放这个引用在堆中的具体地址)
     方法区:可以被所有的线程共享;包含了所有的class和static变量

类的加载

       当程序要使用某个类是,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化。
       加载
             将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象。
             任何类被使用时系统都会建立一个Class对象。
       链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
             验证 是否有正确的内部结构,并和其他类协调一致(确保加载的类信息符合JVM规范,没有安全方面的问题)
             准备 负责为类的静态成员分配内存,并设置默认初始化值(这些内存都将在方法区中进行分配)
             解析 将类的二进制数据中的符号引用替换为直接引用(虚拟机常量池内的符号引用(常量名) 替换为直接引用(地址 )的过程)
       初始化
             执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译期自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造该类对象的构造器)。
             当初始化一个类时,若发现其父类还没有进行初始化,则需要先触发其父类的初始化。
             虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步。

类的初始化

类的主动初始化
       当虚拟机启动,先初始化main方法所在的类
       new一个类的对象
       调用类的静态成员(除了final常量)和静态方法
       调用java.lang.reflect包的方法对类进行反射调用
       当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
       当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当通过子类引用父类的静态变量,不会导致子类初始化
       通过数组定义类引用,不会触发此类的初始化
       引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中)

类加载器

类加载的作用:
       将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表这个类的java,lang,Class对象,作为方法区中类数据的访问入口。
类缓存:
       标准的JavaSE类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,它将维持加载(缓存)一段时间。不过JVM垃圾回收机制可以回收这些Class对象

       Bootstrap ClassLoader 根类加载器
               也被称为引导类加载器,负责Java核心类的加载,用来装载核心类库。该加载器无法直接获取(比如System,String等。在JDK中JRE的lib目录下rt.jar文件中)
       Extension ClassLoader 扩展类加载器
               负责JRE的扩展目录中jar包的加载。(在JDK中JRE的lib目录下ext目录)
       Sysetm ClassLoader 系统类加载器
               负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径;是最常用的加载器
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章