注解和反射
内置注解
- @Overrider:定义在java.lang.Override中,此注释只使用与修辞方法,表示一个方法声明打算重写超类中的另一个方法声明.
- @Deprecated:定义在java.lang.Deprecated中,此注释可以用于修辞方法,属性 类 表示不鼓励程序员使用这样的元素,通常是因为他很危险或者存在更好的选择
- @SuppressWarnings: 定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息.
- 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数都是定义好了的,我们选择性的使用就好了.
- @SuppressWarnings("all")
- @SuppressWarnings("unchecked")
- @SuppressWarnings(value={"unchecked","deprecation})
元注解
- 元注解 的作用就是负责其他注解,java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型做说明.
- 这些类型和他们所支持的类在java.lang.annotation包中可以找到.(@Target,@Retention,@Documented,@Inherited)
- @Target:用于描述注解的使用范围(即:被描述的注解可以用在什么地方,类似作用域详情查看ElementType枚举)
- @Retention:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(source<class<runtime)
- @Documented:说明该注解被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
自定义注解
单个属性 的话尽量使用 value
反射机制
- Reflection(反射)是java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法;
- 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息.我们可以通过这个对象看到类的结构.这个对象就像一面镜子,透过这个镜子看到类的结构,所以我们形象的称之为:反射
正常方式: 引入需要的包类名称->通过new实例化->取得实例化对象
反射方式:实例化对象->getClass()方法->得到完整的"包类"名称
静态 vs 动态语言
- 动态语言:
- 是一类在运行时可以改变其结构的语言:例如新的函数 对象 甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化.通俗点说就是在运行时代码可以根据某些条件改变自身结构.
- 静态语言
- Java不是动态语言,但Java可以称之为'准动态语言'.即java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性.java的动态性让编程的时候更加灵活.
Class类的常用方法
方法名 | 功能说明 |
---|---|
static ClassforName(String name) | 返回指定类名name的class对象 |
Object newInstance() | 调用缺省构造函数,返回Class对象的一个实例 |
getName() | 返回此Class对象所表示的实体(类,接口,数组类或void)的名称 |
Class getSuperClass() | 返回当前Class对象的父类的Class对象 |
Class[] gentinterfaces() | 获取当前class对象的接口 |
ClassLoader getClassLoader() | 返回该类的类加载器 |
Constructor[] getConstructors() | 返回一个包含某些Constructor对象的数组 |
Method getMothed(String name,Class.. T) | 返回一个Method对象,此对象的形参类型为paramType |
Field[] getDeclaredFields() | 返回Field对象的一个数组 |
类的加载与ClassLoader的理解
- 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后生成一个代表这个类的java.lang.Class对象
- 链接:将java类的二进制代码合并到JVM的运行状态之中的过程.
- 验证:确保加载的类信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配.
- 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址) 的过程
- 初始化:
- 执行类构造器
()方法的过程.类构造器 ()方法是有编译器自动收集类中所有类变量的赋值动作和静态代码块中的语句合并产生的.(类构造器是构造类信息的,不是构造该类对象的构造器). - 当初始化一个类的时候,如果发现其父类还没有进行厨师话,则需要先触发其父类的初始化.
- 虚拟机会保证一个类的
()方法在多线程环境中被正确加锁和同步
- 执行类构造器
什么时候会发生类初始化?
- 类的主动引用(一定会发生类的初始化)
- 当虚拟机启动,先厨师话main方法所在的类
- new一个类的对象
- 调用类的静态成员(除了final常量)和静态方法
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果其父类没有被初始化,则会初始化他的父类;
- 类的被动引用(不会发生类的初始化)
- 当访问一个静态域时,只有真正声明这个域的类才会被初始化. 如:当通过子类引用父类的静态变量,不会导致子类初始化
- 通过数组定义类引用,不会触发此类的初始化
- 引用常量不会触发此类的初始化(常量在链接就存入调用类的常量池中了)
类加载器的作用
- 类加载的作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问入口
- 类缓存:标准的javaSe类加载器可以按要求查找类,但一旦某个类被加载到类加载器中,他将维持加载(缓存)一段时间.不过JVM垃圾回收机制可以回收这些Class对象
引导类加载器:用c++编写的,是jvm自带的类加载器,负责java平台核心库,用来装载核心类库.该加载器无法直接获取.
扩展类加载器:负责jre/lib/ext目录下的jar包或-D java.ext.dirs指定目录下的jar包装入工作库
系统类加载器:负责java-classpath 或者 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器