注解与反射
注解:
java.Annotation
Annotation作用:
不是程序本身,可以对程序做出解释。
可以被其他程序读取,比如:编译器等。
Annotation格式:
注解是以“@注解名” 在代码中存在的,还可以添加一些参数。
Annotation使用场景:
可以附加在package,class,method,field 等上面,相当于添加了额外的辅助信息,可以通过反射机制编程实现对元数据的访问。
常用注解:
@Override : 重写注解
@Deprecate : 标记注释,标记注释,就是已经过期或者即将过期的方法。不推荐使用。
@SuppressWarnings : 阻止警告信息。
元注解:
元注解的作用就是负责注解其他注解,java 定义了4个 标准的meat-annotation 类型,他们被用来提供对其他annotation类型作说明。
这些类型和他们所支持的类在: java.lang.annotation 包中可以找到。
注解:
1、@Target : 用于描述注解的使用范围。
2、@Retention : 表示在什么级别保存该注释信息,用于描绘注解的生命周期(SOURCE < ClASS < RUNTIME )。
3、@Document : 说明该注解生成在 JAVAdoc中。
4、@Inherited : 说明子类可以继承父类中的注解。
自定义注解:
使用@interface 自定义注解,自动继承 java.lang.annotation,Annotation 接口。
描述:
@interface 用来声明一个注解,格式:public @interface 注解名 {定义内容}
其中的每一个方法实际上是声明了一个配置参数。
方法的名称就是参数的名称
返回值类型就是参数的类型(返回值只能返回 class,String,enum)
可以通过default 来声明参数的默认值。
如果只有一个参数成员,一版参数名为value
注解元素必须要有值,我们定义注解元素时,经常使用空字符串,0 作为默认值。
代码:

反射机制:
java.Reflection
静态/动态语言描述:
动态语言:
是一类在运行时可以改变其结构的语言:例如:新的函数,对象,甚至代码可以被引进,已有函数可以被删除或是其他结构上的变化。通俗讲,可以在运行时代码可以根据某种条件改变自身结构。
主要动态语言: Object-C,C#,javaScript、PHP、Python 等。
静态语言:
与动态语言相对应的,运行时结构不可以改变的语言就是静态语言。如java、C、C++
java 不是动态语言,但是java 可以称之为”准动态语言“。即java有一定动态性,可以通过反射机制获得类似动态语言的特性。可以让编程更灵活。
反射:
Reflection 是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
加载完类之后,在堆内存的方法区中 就产生了一个 Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。
这个 对象就像是一面镜子,透过这个镜子看到类的结构,所以称之为:反射。
正常方式: 引入需要的”包类“名称 -> 通过new 实例化 ->取得实例化对象。
反射方式: 实例化对象 -> getClass()方法 -> 得到完整的”包类“ 名称。
反射优缺点:
优点: 可以实现动态创建对象和编译 ,灵活性高。
缺点: 对性能有影响,操作慢于直接执行相同 new 操作。
创建Class 对象的方式:
1、通过对象获得。
2、forname 获得。
3、通过类名获得。
注: 基本内置类型的包装类都有一个Type属性(注意 只有内置的对象才有)。
代码:

类的主动引用:
一定会发生类的初始化。
场景:
1、调用类的静态成员(除了final常量) 和静态方法。
2、当虚拟机启动,先初始化Main所在的类。
3、new 一个 类的对象。
4、当初始化一个类,如果父类没有被初始化,则会先初始化父类。
类的主动引用:
不会发生类的初始化。
场景:
1、当访问一个静态域时,只有真正声明这个域的类才会被初始化。如:当子类引用父类的静态变量。
2、通过数组定义类引用,不会触发类的初始化。
3、引用常量不会触发此类的初始化。
类加载器的作用:
将class 文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据集结构,在堆中生成一个代表这个类的java.lang.Class类型的对象。
类缓存: 标准的javaSE类加载器可以按要求查找类,但是一旦类被加载到类加载器中,他将维持加载(缓存)一段时间。不过JVM回收机制可以回收这些Class对象。
代码:

双亲委派机制:
通俗来讲就是 定义类之后 ,系统会一级一级往上找如果根加载器 存在你定义的类,则抛出异常,此类无效。
通过反射获取类的基本属性:
一、 获取类名称:
1、Class.getName() : 获取类路径 + 名称。
2、Class.getSimpleName() : 获取类名称。
二、获取类属性:
1、Class.getFields() : 获取类 Public 属性。 带参数就是获取指定参数。
2、Class.getDeclaredFields() : 获取类所有属性,包括 private 。带参就是获取指定属性。
三、获得类的方法:
1、Class.getMethods() : 获取本类及其父类所有public 方法。
2、Class.getDeclaredMethods() : 获取本类所有方法。
3、Class.getMethods(“参数”,类型): 获取指定方法,因为有重载的可能性,所以需要加入参数。
四、获取类的构造器
1、Class.getConstructors(): 获取所有Public 构造器。
2、Class.getDeclaredConstructors() : 获取本类所有构造器。
代码:

通过反射创建对象:
Class<?> aClass = Class.forName("Study_2021_08_17.reflection.User");
User user = (User) aClass.newInstance(); //默认调用无参构造 ,如果没有无参构造则报错
System.out.println(user);
// 通过构造器创建对象
Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(String.class, String.class);
User user1 = (User) declaredConstructor.newInstance("张三", "1234141");
System.out.println(user1);
//通过反射调用普通方法
User user2 = (User) declaredConstructor.newInstance("张三", "1234141");
//通过反射获取一个方法
Method setName = aClass.getDeclaredMethod("setName", String.class);
//invoke: 激活的意思
// (对象,”方法的值“)
setName.invoke(user2, "李四");
System.out.println(user2);
// 通过反射获取属性 : 不能直接操作私有属性。如果需要操作 ,需要关闭程序的安全检测,通过方法或者属性的 setAccessible(true)来关闭,可以调高效率。
Field name = aClass.getDeclaredField("name");
//name.setAccessible(true);
name.getName();
name.set(user2, "王五");
System.out.println(user2);
反射性能测试:
/**
* @description: 反射性能测试
* @author: zhx
* @created: 2021/08/18 22:00
*/
public class Test09 {
// 普通调用
public static void test01() {
User user = new User();
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
user.getName();
}
long endTime = System.currentTimeMillis();
System.out.println("普通方法调用执行时间:" + (endTime - startTime) + "ms");
}
// 反射
public static void test02() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<?> aClass = user.getClass();
Method getName = aClass.getDeclaredMethod("getName", null);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user, null);
}
long endTime = System.currentTimeMillis();
System.out.println("反射调用执行时间:" + (endTime - startTime) + "ms");
}
// 反射 关闭检测
public static void test03() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
User user = new User();
Class<?> aClass = user.getClass();
Method getName = aClass.getDeclaredMethod("getName", null);
getName.setAccessible(true);
long startTime = System.currentTimeMillis();
for (int i = 0; i < 100000000; i++) {
getName.invoke(user, null);
}
long endTime = System.currentTimeMillis();
System.out.println("关闭权限检测:" + (endTime - startTime) + "ms");
}
public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException {
test01();
test02();
test03();
/**
* 结果:
* 普通方法调用执行时间:11ms
* 反射调用执行时间:561ms
* 关闭权限检测:347ms
*/
}
}

浙公网安备 33010602011771号