Java_注解与反射
C1.概述
-
注解(Annotation)
-
作用:
-
不是程序本身,可以对程序做出解释
-
这点和注释(Comment)一样
-
-
可以被其它程序读取
-
比如:编译器
-
-
-
格式:
-
@注释名
-
@注释名(value="unchecked")
-
-
使用的地方:
-
package
-
class
-
method
-
field
相当于给它们添加了额外的辅助信息;
我们可以通过反射机制编程实现对这些元数据的访问
-
C2.内置注解
-
@Override
-
定义在
java.lang.Override
中 -
只能修饰方法
-
表示一个方法声明打算重写超类中的另一个方法声明
-
-
@Deprecated
-
定义在
-
可修饰方法、属性、类
-
表示不鼓励程序员使用这样的元素,通常是因为它很危险或者存在更好的选择
-
-
@SupperWarnings
-
定义在
java.lang.SupperWarnings
中 -
用来抑制编译时的警告信息
-
必须要有参数
-
例子:
-
@SupperWarnings("all")
-
@SupperWarnings("unchecked")
-
@SupperWarnings(value={"unchecked", "deprecation"})
-
-
C3.元注解
-
元注解 => 负责注解其它注解
-
在
java.lang.annotation
包中 -
1)
@Target
-
描述注解的使用范围
-
-
2)
@Retention
-
表示需要在什么级别保存该注释信息
-
用于描述注解的生命周期
-
-
SOURCE
<CLASS
<RUNTIME
-
-
3)
@Documented
-
说明该注解将被包含在Javadoc中
-
-
4)
@Inherited
-
说明子类可以继承父类中的该注解
-
package demo;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
C4.自定义注解
-
使用
@interface
自定义注解时,自动继承了java.lang.annotation.Annotation
接口 -
自定义注释的格式:
public @interface 注释名 { 定义内容 }
-
其中的每一个方法实际上是声明了一个配置参数
-
方法的名称 => 参数的名称
-
返回值类型 => 参数类型
-
default
=> 声明参数的默认值 -
如果只有一个参数成员,一般参数名为
value
-
注解元素必须要有值
-
我们定义注解元素时,通常使用空字符串、0作为默认值
-
-
-
package demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
P2.反射
C1.概述
-
“动态语言”与“静态语言”:
-
动态语言:
-
在运行时可以改变其结构
-
例如新的函数、对象,甚至代码可以被引进,已有的函数可以被删除或者其他结构上的变化
-
即,在运行时代码可以根据某些条件改变自身接哦股
-
-
如:C#、Js、PHP、Python等
-
-
静态语言:
-
运行时结构不可变的语言
-
如:Java、C、C++
-
准动态语言
-
Java具有一定的动态性
-
我们可以通过反射机制获得类似动态语言的特性
-
-
-
-
反射机制允许程序在执行期间,借助Reflection API取得任何类的内部信息,并直接操作任意对象的内部属性及方法
-
加载完类后,在堆内存的方法区中就会产生一个Class类型的对象
-
一个类只有一个Class对象
-
该对象包含了完整的类的结构信息
-
通过这个类能够看到类的结构
-
-
-
优缺点:
-
优点:
-
可以动态实现创建对象和编译,体现出很大的灵活性
-
-
缺点:
-
对性能有影响
-
反射基本上是一种解释操作
-
我们告诉JVM希望它做什么,并且使它满足我们的要求
-
这类操作往往慢于直接执行相同的操作
-
-
-
-
-
反射相关的主要API
-
java.lang.Class
-
java.lang.reflect.Method
-
java.lang.reflect.Field
-
java.lang.reflect.Constructor
-
C2.理解Class类并获取Class实例
-
Class对象只能由系统建立对象
-
一个Class对象对应的是一个加载到JVM中的一个.class文件
-
每个类的实例都会记得自己是由哪个Class实例所生成
-
通过Class类可以完整的得到一个类中所有被加载的结构
-
Class类是Reflection的根源,任何你想动态加载、运行的类,唯有先获得相应的Class对象
-
Class类的常用方法:
-
-
哪些类型可以有Class对象?
-
class
-
interface
-
数组
-
只要元素类型同,即使数组长度不同,它们的Class都一样
-
-
enum
-
annotation
-
primitive type
-
void
-
C3.类的加载与ClassLoader
-
Java内存:
-
类加载的过程
-
什么时候发生类初始化:
// 获取系统类的加载器
ClassLoader appClassLoader = ClassLoader.getSystemClassLoader();
System.out.println("<appClassLoader>\r\n" + appClassLoader);
// 获取系统类加载器的父类加载器 => 扩展类加载器
ClassLoader extClassLoader = appClassLoader.getParent();
System.out.println("<extClassLoader>\r\n" + extClassLoader);
// 获取扩展类加载器的父类加载器 => 根加载器
// 因为是C/C++编写的,所以Java获取不到
ClassLoader rootClassLoader = extClassLoader.getParent();
System.out.println("<rootClassLoader>\r\n" + rootClassLoader);
// 测试当前类是哪个类加载器加载的
ClassLoader curClassLoader = Class.forName("demo.Test03").getClassLoader();
System.out.println("<curClassLoader>\r\n" + curClassLoader);
// 测试jdk内置类是哪个类加载器加载的
ClassLoader objClassLoader = Class.forName("java.lang.Object").getClassLoader();
System.out.println("<jdk内置类的ClassLoader>\r\n" + objClassLoader);
// 如何获得系统类加载器可以加载的路径
System.out.println("系统类加载器可以加载的路径");
System.out.println(System.getProperty("java.class.path"));
<appClassLoader>
sun.misc.Launcher$AppClassLoader@73d16e93
<extClassLoader>
sun.misc.Launcher$ExtClassLoader@15db9742
<rootClassLoader>
null
<curClassLoader>
sun.misc.Launcher$AppClassLoader@73d16e93
<jdk内置类的ClassLoader>
null
系统类加载器可以加载的路径
D:\Program Data\workspace\Eclipse\02.NewStudy_Java\7.Annotation\bin
C4.创建运行时类的对象
-
调用Class对象的newInstance()方法
-
类必须有一个无参的构造函数
-
类的构造函数的访问权限必须要足够
-
-
如果反射比较多的话,建议关闭“检测”,这样能够提升效率
C5.获取运行时类的完整结构
-
通过反射获取完整的运行时类结构
-
Field、Method、Constructor、Superclass、Interface、Annotation......
C6.调用运行时类的指定结构
反射操作泛型
-
泛型 => 一种约束机制
-
Java采用的是泛型擦除机制来引入泛型
-
仅仅是给编译器javac使用的
-
一旦编译完成,所有和泛型有关的类型全部擦除
-
-
确保数据的安全性和免除强制类型
-
-
为了通过反射操作这些类型,Java新增了ParameterizedType、GenericArrayType、TypeVariable、WildcardType几种类型,用于代表不能被归一到Class类中的类型,但是又和原类型齐名的类型
-
ParameterizedType
-
表示一种参数化类型,如
Collection<String>
-
-
GenericArrayType
-
表示一种元素类型是参数化类型或者类型变量的数组类型
-
-
TypeVariable
-
各种类型变量的公共父接口
-
-
WildcardType
-
代表一种通配符类型表达式
-
-
-
获得方法泛型参数的类型:
method.getGenericParameterTypes();
package demo;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
public class Test05 {
public void test01(Map<String, User> map, User<Integer> user) {
}
public Map<String, User> test02() {
return null;
}
public static void main(String[] args) throws NoSuchMethodException, SecurityException {
Method method = Test05.class.getMethod("test01", Map.class, User.class);
Type[] genericParameterTypes = method.getGenericParameterTypes();
for (Type type : genericParameterTypes) {
System.out.println("\r\n#" + type);
if (type instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (Type type2 : actualTypeArguments) {
System.out.println(type2);
}
}
}
Method method2 = Test05.class.getMethod("test02", null);
Type genericReturnType = method2.getGenericReturnType();
System.out.println("\r\n#" + genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type type2 : actualTypeArguments) {
System.out.println(type2);
}