Skip to content

Latest commit

 

History

History
195 lines (190 loc) · 11 KB

01注解与反射.md

File metadata and controls

195 lines (190 loc) · 11 KB

01 注解 · 注解是jdk5.0开始引入的新技术 · 作用:

  1. 不是程序本身, 可以对程序作出解释, 这一点与注释类似;
  2. 可以被其他程序(如编译器)读取, 附加信息, 检查跟约束 · 格式: @注解名(参数列表) eg. @SuppressWarnings(value="unchecked") · 可以在哪里使用 可以附加在 package class method field 上, 相当于给他们附加了额外的信息, 检查跟约束 可以通过反射机制, 编程实现对这些元数据的访问 2 注解的例子 实现接口 继承类的时候的[重写 @Override 就是一种注解] 3 内置注解 @Override 加在方法上 @Deprecated 使用这个注解的方法或者属性在使用的时候会被划上横线, 表示过时废弃; 加在方法上 表示不鼓励程序员使用, 通常是存在危险, 或是存在更好的选择 @SuppressWarnings("all") "unchecked" value={"uncheck","deprecation"} 加在方法上和类上 4 元注解 作用:负责注解其他注解, java定义了四个标准的meta-annotation来用于对其他注解提供说明 [主要用于自定义注解的时候, 对自定义的注解进行说明] 存在位置: java.lang.annotation. 分别是: @Target @Retention @Documented @Inherited @Target: 说明该注解的使用范围, 表示注解可以用在什么地方 TYPE 、 FIELD 、METHOD 、PARAMETER 、CONSTRUCTOR 、 LOCAL_VARIABLE ANNOTATION_TYPE 、PACKAGE @Retention: 表示需要在什么级别保存该注解信息, 用于描述注解的声明周期.(RUNTIME>CLASS>SOURCE) @Documented: 说明该注解将被包含在javadoc中 @Inherited: 说明子类可以[继承]父类中的该注解 5.自定义注解使用@interface, 就自动继承了java.lang.annotation.Annotationo接口 · @interface用来声明一个注解, 格式: @元注解 public @interface 注解名 {定义内容} · 里面的每一个方法实际上是声明了一个配置参数, 方法的名称就是参数的名称, 方法的返回类型就是参数的类型, 只能是基本类型(Class, String, enum) 可以使用default 来声明参数的默认值 如果只有一个(成员)参数, 一般命名为value, 这样使用的时候就可以省略参数指定 · 注解元素一定要有值(没有默认值的 一定要在使用时指定) 一般使用""空字符串, 0 等作为默认值

02 反射机制 · 动态语言: 运行的时候可以改变其结构: [运行的时候可以引进新的函数、对象、代码; 已有的函数可以被删除或是其他结构上的变化] 例如JavaScript/Object-C/C#/PHP/Python 在javascript中可以使用eval("")方法把字符串解析成一段代码 · 静态语言 java c c++
java不是动态语言, 但是可以称为"准动态语言", 可以使用反射机制来获得类似静态语言的特性; 但是相对不安全 · Java Reflection 1)java反射机制允许程序在运行期间借助于Reflection API取得任何类的内部信息, 并能操作任意对象的内部属性和方法 2)在加载完类之后, 在堆内存的方法区就产生了一个Class类型的对象(一个类只有一个Class对象) 这个Class对象就包含了完整的结构信息, 通过这个对象可以看到类的结构 正常方式: import包 --> 通过new实例化 --> 取得类的实例对象 反射方式: 实例化对象--> getClass()方法-->取得完整的包类名称 · 反射机制的一些功能

  1. 在运行时 判断任意一个对象所属的类; 构造任意类型的对象; 判断任意一个类所具有的成员变量和方法; 获取泛型信息; 调用任意一个对象的成员变量和方法; 处理注解
  2. 生成动态代理 · 优点: 实现动态的创建对象和编译, 灵活 缺点: 对性能有影响, 反射基本是一种解释型操作 · 相关的主要API java.lang.Class 代表一个类 java.lang.reflect.Method 代表类的方法 java.lang.reflect.Field 代表类的成员变量 java.lang.reflect.Constructor 代表类的构造器 · Class类
  3. 本身也是一个类
  4. 只能由系统建立对象
  5. 一个加载的类在JVM中只有一个Class实例
  6. 一个Class对象对应的是一个加载到JVM的.class文件
  7. 每一个类的实例都知道自己是由哪个Class实例所生成
  8. 通过Class可以完整的得到一个类中的所有被加载的结构
  9. Class对象时Reflect的根源, 任何你想动态加载、运行的类, 都需要先获得他的Class对象 ·Class类常用的方法 static ClassforName(String name) 返回指定类名name的Class对象 class实例方法 Object newInstance() 调用缺省构造函数, 返回Class对象的一个实例 String getName() 返回Class对象所表示的实体(类、接口、数组类或者void)的名称 Class getSuperClass() 返回当前Class对象的父类的Class对象 Class[] getInterfaces 获取当前Class对象的接口 ClassLoader getClassLoader() 返回该类的类加载器 Constructor[] getConstructors() 返回包含某些Constructor对象的数组 Method getMethod(String name, Class..T)返回一个Method对象, 方法的形参类型为paramType field[] getDeclaredField() 返回Field对象的一个数组 · 哪些类有Class对象
  10. 所有的类class: 外部类、成员(成员内部类、静态内部类) 局部内部类 匿名内部类
  11. 所有的接口Interface
  12. 所有的数组[]
  13. 枚举enum
  14. 注解annotation @interface
  15. primitive type 基本数据类型
  16. void · [内存分析] java的内存分为:
  17. 堆: 存放new的对象和数组 可以被所有的线程共享, 不会存放别的对象引用
  18. 栈: 存放基本类型变量(包含这个基本类型变量的数值) 引用对象的变量(会存放这个引用在堆里的具体地址)
  19. 方法区(特殊的堆): 可以被所有的线程共享 包含了所有的class和静态static变量 · 类的加载过程 当程序主动使用某个类的时候, 如果该类还没有被加载到内存中, 则通过一下三个步骤进行该类的初始化
  20. 类的加载(load) 将类的class文件读入内存, 并为之创建一个java.lang.Class对象, 此过程由类加载器完成
  21. 类的链接(Link) 将类的二进制数据合并到JRE中 ①验证: 确保加载的类的信息符合JVM规范, 没有安全方面的问题 ②准备: 正式为类变量(static)分配内存并设置变量默认初始值的阶段, 这些内存都将在方法区中进行分配 ③解析: 虚拟机常量池的符号引用(常量名), 替换为直接引用(地址)的过程
  22. 类的初始化 JVM负责对类进行初始化 ①执行类构造器()方法的过程, 类构造器()方法是由编译期自动收集的 类中所有类变量的赋值动作和静态代码块中的语句合并产生的, ②当初始化一个类的时候, 如果发现其父类还没有初始化, 则需要先触发其父类的初始化 ③虚拟机会保证一个类的()方法在多线程的环境中被正确的加锁和同步 // 4.类的加载 /**
  • 1.加载.class文件到内存[方法区], 在[堆里]会产生一个这个类对应的Class对象
  • 2.链接 [栈中]static变量分配初始值 m=0
  • 3.初始化 合并静态块和静态方法
  • static{
    
  •     System.out.println("A类静态代码块初始化");
    
  •     m = 300;
    
  • }
    
  • static int m = 100;
    
  • <clinit>{
    
  •     System.out.println("A类静态代码块初始化");
    
  •     m = 300;
    
  •     m = 100;
    
  • }
    
  • m = 100;
    
  • 调换两者顺序 则结果m的值发生改变
    

*/ · 什么时候会发生类的初始化 第二个测试类ReflectTest02.java I.类的主动引用(一定会发生类的初始化)

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

· 类加载器的作用 第三个测试类ReflectTest03.java

  1. 将.class文件字节码内容加载到内存中, 并将这些静态数据转为方法区的[运行时数据结构], 然后在堆中生成一个代表这个类的java.lang.Class对象, 作为方法区中类数据的访问路口
  2. 类缓存: 标准的javaSE类加载器可以按要求查找类, 但一旦某个类被加载到类加载器中, 将维持加载(缓存)一段时间, JVM的垃圾回收机制GC会回收这些Class对象 源程序.java文件--->Java编译器--->字节码.class文件--->类加载器--->字节码校验器--->解释器--->操作系统OS平台 · 有哪些类加载器
  3. 引导类加载器: 用C++编写的, 是JVM自带的类加载器, [负责java平台核心库rt.jar包], 用来装载核心类库, 该加载器无法直接获取
  4. 扩展类加载器: 负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包 装入工作库
  5. 系统类加载器: 负责java -classpath或者-D java.class.path所指目录下的类与jar包 装入工作库 是最常用的类加载器 由1)-3)尝试加载类, 由3)-1)检查类是否已经被加载 · [双亲委派机制] 如果自己写一个java.lang.String类,会逐级检查, 先检查系统类加载器/再检查扩展类加载器/在检查根加载器, 如果发现有java.lang.String类, 则自己写的java.lang.String类不会生效 多重检测, [证安全性]

· 获得类的运行时数据结构 第四个测试类ReflectTest04.java · 通过Class对象构造对象执行方法 第五个测试类ReflectTest05.java · 反射性能测试 第六个测试类ReflectTest06.java

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

·反射操作注解 第八个测试类ReflectTest08.java getAnnotations getAnnotation 练习对象关系映射(Object Relationship Mapping, ORM) java代码程序中的对象 和 数据库中存储的关系 的映射