注解和反射

一、注解:

1.1、什么是注解

注释(Comment):给人看的
注解(Annotation安娜忒瞬):给程序解释

JDK5.0开始引入的技术
作用:

  1. 不是程序本身,可以堆程序作出解释
  2. 可以被其他程序(比如:编译器)读取。

格式:
@注释名,还可以添加一些参数值

1.2、内置注解

@Override  //重写超类另一个方法的声明
@Deprecated //表示不推荐使用,通常是它很危险或者存在更好的选择
@SuppressWarnings//抑制警告
/*
与前两个注解有所不同,你需要添加一个参数才能正常使用,这些参数都已经顶i约好了,我们选择性使用就好了
@SuppressWarnings("all")
@SuppressWarnings(value={"all","deprecation"})
等
*/

注解和反射_第1张图片
注解和反射_第2张图片

1.3、元注解:注册其他注解的注解

作用:负责注册其他注解的注解
Java中定义了4个标准的meta-annotation类型
这些类型和它们所支持的类可以在Java.lang.annotation包中可以找到(@Target,@Retention,@Documented,@Inherited(音嘿瑞得的))
注解和反射_第3张图片

1.4、自定义注解

使用@Interface自定义注解时,自动继承java.lang.annotation.Annotation接口

注解和反射_第4张图片
注解和反射_第5张图片
如果一个注解只有一个参数value的话,那么在使用注解的时候不用写参数名字,如果不是参数名不是value的话使用的时候就需要写参数名字

如何去读取注解?
我们可以通过反射机制编程去实现堆这些元数据的访问。

二、反射机制

学这个之前我觉得我先搞懂,Class对象、实例对象、引用对象之间的区别

Person person;
person = new Person("张三");
person = new Person("李四");
Person person2 = person;

person对象的引用存放在栈上,new Person才是真正创建了对象的实例存放在堆上
一个引用可以指向多个对象,而一个对象可以被多个引用所指

正常:实例对象是通过类创造出来的,任何类只有一个Class对象
反射:实例对象可以得到他的Class对象
当然一切的前提是要有这个类

2.1、反射机制的概述

什么是反射,为什么要学习反射,反射的作用

静态语言和动态语言

动态语言:运行时可以改变自身结构的语言(js、PHP、python、C#等)
静态语言:运行时结构不可变的语言(JAVA、C、C++)
注解和反射_第6张图片
js:eval方法,在程序运行的时候改变这段x对象的值,本来是个string,执行完这段string,x变成了数字。

Java不是动态语言,但是因为有反射机制可以称之为“准动态语言”,即Java有一定的动态性,我们可以利用反射机制获得类似动态语言的特性。Java的动态性让编程的时候更加灵活。
缺点:增加了不安全性

反射概述:

类的内部信息(类名、类的接口、方法、属性等)
注解和反射_第7张图片
正常:class对象通过new得到实例化对象
反射:实例化对象getclass()得到class对象

之前说Java类变成Class之后就不能变了,但是有反射可以

反射机制提供的功能

注解和反射_第8张图片

反射的优点和缺点

优点:可以实现动态创建对象和编译,体现出强大的灵活性
缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

反射相关的主要API

注解和反射_第9张图片

注解和反射_第10张图片

2.2、理解Class类并获得Class实例

可以通过引用对象反射求出类的名称,每个类可以有很多引用对象但是只有一个相对应的Class类
注解和反射_第11张图片

对象getClass()后得到class对象
注解和反射_第12张图片

Class类的常用方法

newInstance()通过反射来创建一个引用对象,跟new一个对象是一样的
注解和反射_第13张图片

得到Class类的几种方式

注解和反射_第14张图片
注解和反射_第15张图片

哪些类型可以有Class对象?

几乎所有的类
注解和反射_第16张图片
注解和反射_第17张图片
只要元素类型与维度一样,就是同一个Class
注解和反射_第18张图片

2.3、类的加载ClassLoader内存分析

Java类的底层是什么实现
注解和反射_第19张图片
方法区是一个特殊的堆
堆、方法区可以被所有线程共享
堆存放new出来的实例对象和数组
方法区存放所有的class和static变量
栈存放基本类型变量和引用对象变量,不能被所有线程共享

类加载过程

注解和反射_第20张图片
类的链接:将类的数据合并到Java的运行时环境中
详解:
问题:为什么static在没有类就直接直接调用?
因为他是在初始化之前就直接存在了 (链接:准备阶段)

注解和反射_第21张图片

静态代码块和静态变量执行先后顺序取决于代码编写的顺序

示例:
注解和反射_第22张图片
注解和反射_第23张图片

1、类加载时class对象就形成了:首先类写好后他会编译成class字节码文件加载到内存,并将静态数据转换成方法区中运行时数据结构(Test05类的数据、A类的数据),加载完成后立马会生成一个代表这个类的Java.lang.Class对象在堆中

2、然后执行main()在栈中执行,首先m设置类变量默认的初始值0(链接阶段第二步准备)也在栈中

3、然后执行第一句new A()在堆中,创建了一个A类的实例对象指向A类的Class然后就会拿到A类的所有数据,然后通过这些数据给A类赋值开始初始化,初始化的时候JVM执行一个构造器()方法,他会把静态代码块和初始值都给合并了所以先m=300然后m=100所以最后打印出来的值是m=100,栈中的m也是这么变化的最后为100

简介:首先在方法区里面产生了这个类的一些静态数据,加载到类的时候就产生了Class对象,然后开始执行main方法,main方法开始链接m有个默认初始值是0,当链接执行完所有工作准备完确定代码没问题的时候于是我们开始执行代码,执行代码new A,产生了一个A类的对象,这个对象就会去找他的那个Class类,这个类代表他的一个类的结构,我们去这个类的结构里面,通过这个A类的具体东西给他赋值,赋值完之后通过clinut()方法初始化,初始完之后m就有一个初始值咱们就可以打印出来了

2.4、分析类初始化

我们刚刚了解了一下类是如何加载的三步:加载、链接、初始化
现在来分析一下初始化

什么时候会发生类的初始化

类分为主动引用被动引用

注解和反射_第24张图片
示例:
注解和反射_第25张图片
注解和反射_第26张图片
注解和反射_第27张图片

2.5、类加载器的作用

注解和反射_第28张图片
类缓存:缓存一段时间,当我们不需要JVM就会垃圾回收这些class对象
注解和反射_第29张图片
根(引导)类加载器:Java运行环境jre/lib/rt.jar
注解和反射_第30张图片
扩展类加载器:jre/lib/ext
注解和反射_第31张图片
系统类加载器:
注解和反射_第32张图片
注解和反射_第33张图片
在这里插入图片描述

打印类加载器可以加载的类路径:只有在这些路径才能被加载,程序不是凭空能运行的是由类加载器一步一步加载出来才能用
注解和反射_第34张图片
双亲委派机制:我们自定义一个类要加载,他会去上面找先找系统加载器有没有这个包类,然后再找扩展加载器有没有这个包类,最后再找根加载器有没有这个包类
比如我们定义一个java.lang.String类,然后根加载器已经加载了一个java.lang.String类然后就会加载根加载器的String类而不会加载我们自定义的。
好处:多重检测保证一个安全性。

2.6、获得运行时类的完整结构

反射可以获得运行时类的:属性、方法、构造器、父类、接口、注解、
还有包名+类名、类名
注解和反射_第35张图片
Declared(第可兰德)
异常:NoSuchFieldException 用getField去找private修饰的属性的时候找不到报出来的异常

c1是用全类名反射获得的User类,User类有三个私有属性(id、age、name),两个公共的构造器,一个公共的toString方法,三个属性的get、set方法

注解和反射_第36张图片
当使用getMethods的时候会获得本类及父类(至少会获得Object的方法)的全部public方法
获得有参数的方法需要传值,因为重载的存在需要通过传值确定方法
注解和反射_第37张图片
获得构造器:
注解和反射_第38张图片

2.7、动态的创建对象,反射操作方法属性

注解和反射_第39张图片
示例:
获得实例对象:
注解和反射_第40张图片
通过反射调用普通方法
注解和反射_第41张图片
通过反射调用属性
注解和反射_第42张图片

为什么要这么麻烦用反射操作方法属性这样,不直接用对象.方法操作?
原因1:动态代理AOP可以直接在代理类进行这些操作,保持原对象的代码不被修改,降低程序的耦合性
原因2:直接调用相当于写死在代码中了,配置化开发的时候这种方式可以从外部传入任意的方法名和参数来执行方法

反射的作用和泛型有些类似,灵活性高,避免写冗余的代码,特别写公共部分很实用

IllegalAccessException非法存取异常:因为类是私有的用getDeclaredField可以获取,但是在修改的时候因为Java语言安全检测判定private不能直接通过反射存取所以报错IllegalAccessException
解决方法:setAccessible方法去关掉安全检测

注解和反射_第43张图片
注解和反射_第44张图片

setAccessiable

注解和反射_第45张图片

分析性能对比(普通方法,反射方法,关闭检测的反射方法)

注解和反射_第46张图片

调用user类的getName方法10亿次测试结果如下:
注解和反射_第47张图片
1s=1000ms
反射调用的比较多的话建议关闭安全检测

反射操作泛型

test01泛型参数
test02泛型返回值

操作方法泛型参数:
1、获得方法
2、获得泛型参数类型
3、遍历打印
4、循环内判断,泛型的参数类型是否是参数化类型
5、是的话就强转成参数化类型,然后调用方法获得参数化信息
6、遍历打印参数化信息

操作返回类型泛型:
同上
注解和反射_第48张图片
输出:
注解和反射_第49张图片
反射:约束机制,泛型在编译完成后会擦除
作用:确保安全性,免去强制转换
注解和反射_第50张图片
了解即可扩展

反射操作注解

注解和反射_第51张图片
在这里插入图片描述
示例:
注解类:
注解和反射_第52张图片
注解和反射_第53张图片
实体类:有参数无参构造器,getset方法,tostring
注解和反射_第54张图片
操作类:
注解和反射_第55张图片

测试:
注解和反射_第56张图片
我们以后用到框架都是这么写的,他们会在类里面定义大量的注解,然后通过反射框架读取注解,然后生成相应的信息

案例假设:假设数据库中有这样一张表,可以用注解定义跟这张表对应的类型,然后通过注解生成数据库语言进行增删改查自动创建表都是可以的。

总结

注解:什么是注解,比起注释有一个可以被程序读取的功能,通过反射可以读取注解

内置注解:主要讲了个@suppresswarnings

自定义注解@interface

元注解@Target、@Retention


反射机制:
静态语言、动态语言

什么是反射

为什么他叫做反射

反射能干什么

反射主要的API

Class类:无论多少个对象只有一个Class类

Class类的常用方法

Java的内存分析:
类如何加载过程:加载、链接、初始化

问题:为什么static在没有类就直接直接调用?
因为他是在初始化之前就直接存在了 (链接:准备阶段)

类加载器:根加载器、扩展类加载器、系统类加载器
双亲委派机制

创建运行时类的对象
获取类的完整结构:属性、方法、构造器、父类、接口、泛型、注解
如何创建一个对象:newInstance()还有可以通过构造器
调用指定的方法invoke()
修改private的调用setAccessible方法

反射如何操作泛型
反射操作注解:注解代表表的信息,通过反射读取注解的值获取出来,然后我们可以通过这些值,动态的生成sql语句,比较高级的功能

注解和反射只有框架的底层会慢慢的巩固他。

你可能感兴趣的:(Java基础学习,java)