实际案例
:
*
概念:针对
Java
编译器的说明
*
注释:⽤⽂字描述程序的。给程序员看的
*
定义:注解(
Annotation
),也叫元数据。⼀种代码级别的说明。它是
JDK1
.
5
及以后版本引⼊的⼀个特性,与
类、接⼝、枚举是在同⼀个层次。它可以声明在包、类、字段、⽅法、局部变量、⽅法参数等的前⾯,⽤来对这些元素
进⾏说明,注释。
*
概念描述:
*
JDK1
.
5
之后的新特性
*
针对
Java
编译器的说明
*
使⽤注解:
@
注解名称
//使⽤框架的类
@Controller
public class UserController extends BaseController{
@Autowired
UserService userService;
@RequestMapping("/user/toLogin.action")
public String toLogin() {
return "/login.jsp";
}
@RequestMapping("/user/login.action")
public String login(User user,Model model,HttpServletRequest request) {
Map<String,String> map=new HashMap<String,String>();
map.put("name", user.getName());
map.put("password", user.getPassword());
if(userService.findUserByName(map)) {
request.getSession().setAttribute("user","jiang");
return "/admin/index.jsp";
}
model.addAttribute("errorMsg", "登录失败!账号或密码错误!");
return "/login.jsp";
}
2.
注解作⽤分类:
①编写⽂档:通过代码⾥标识的注解⽣成⽂档【⽣成⽂档
doc
⽂档】
示例
:
doc
⽂件⽣成的命令
:
②代码分析:跟踪代码依赖性,实现替代配置⽂件功能
,
⽐较常⻅的是
spring 2.5
开始的基于注解配置。
//
普通的类
public class
Anno
{
@Override
public
String
toString
() {
return super
.
toString
();
}
}
/**
*
这⾥⼀个注解的类使⽤
* @author
⼩灰
* @version 1.0
* @since 1.5
*/
public class
Anno
{
/**
*
这⾥⼀个计算总合的⽅法
* @param a
参数
1
* @param b
参数
2
* @return
返回值
*/
public
int
addSum
(
int
a
,
int
b
) {
return
a
+
b
;
}
}
-
javadoc
③编译检查:通过代码⾥标识的注解让编译器能够实现基本的编译检查【
Override
】
作⽤总结
:
3.JDK
中预定义的⼀些注解
@Override
:检测被该注解标注的⽅法是否是继承⾃⽗类
(
接⼝
)
的
@RequestMapping
(
"/user/login.action"
)
public
String
login
(
User user
,
Model model
,
HttpServletRequest request
) {
Map
<
String
,
String
>
map
=
new
HashMap
<
String
,
String
>
();
map
.
put
(
"name"
,
user
.
getName
());
map
.
put
(
"password"
,
user
.
getPassword
());
if
(
userService
.
findUserByName
(
map
)) {
request
.
getSession
().
setAttribute
(
"user"
,
"jiang"
);
return
"/admin/index.jsp"
;
}
model
.
addAttribute
(
"errorMsg"
,
"
登录失败!账号或密码错误!
"
);
return
"/login.jsp"
;
}
//
普通的类
public class
Anno
{
@Override
public
String
toString
() {
return super
.
toString
();
}
}
①编写⽂档:通过代码⾥标识的注解⽣成⽂档【⽣成⽂档
doc
⽂档】
②代码分析:通过代码⾥标识的注解对代码进⾏分析【使⽤反射】
③编译检查:通过代码⾥标识的注解让编译器能够实现基本的编译检查【
Override
】
*
@Override
:检测被该注解标注的⽅法是否是继承⾃⽗类
(
接⼝
)
的
*
@Deprecated
:该注解标注的内容,表示已过时
*
@SuppressWarnings
:压制警告
*
⼀般传递参数
all
@SuppressWarnings
(
"all"
)
//
普通的类
public class
Anno
{
@Override
public
String
toString
() {
return super
.
toString
();
}
}
@Deprecated
:该注解标注的内容,表示已过时
@SuppressWarnings
:压制警告
*
⼀般传递参数
all @SuppressWarnings("all")
@SuppressWarnings
(
"all"
)
//
加类身上代表类中所有的警告忽略
public class
Anno2
{
@Override
public
String
toString
() {
return super
.
toString
();
}
//
第⼀版写的类
/**
*
这个版本过期了
,
建议后期使⽤
show2()
⽅法
*/
@SuppressWarnings
(
"all"
)
//
加⽅法身上代表⽅法上的所有警告忽略
@Deprecated
public
void
show1
() {
//
后期发现这个⽅法有些问题
System
.
out
.
println
(
"
第⼀版⽅法
"
);
}
//
第⼆版写的类
public
void
show2
() {
//
改善版的类
System
.
out
.
println
(
"
第⼆版⽅法
"
);
}
}
预定义注解总结
:
4.
⾃定义注解
格式
:
参考系统的注解
:
本质:注解本质上就是⼀个接⼝,该接⼝默认继承
Annotation
接⼝
测试
1.
定义注解
2.
反编译后代码
*
@Override
:检测被该注解标注的⽅法是否是继承⾃⽗类
(
接⼝
)
的
*
@Deprecated
:该注解标注的内容,表示已过时
*
@SuppressWarnings
:压制警告
*
⼀般传递参数
all
@SuppressWarnings
(
"all"
)
元注解
public @interface
注解名称
{
属性列表
;
}
@Documented
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
value
=
{
CONSTRUCTOR
,
FIELD
,
LOCAL_VARIABLE
,
METHOD
,
PACKAGE
,
PARAMETER
,
TYPE
})
public @interface
Deprecated
{
}
@Target
({
TYPE
,
FIELD
,
METHOD
,
PARAMETER
,
CONSTRUCTOR
,
LOCAL_VARIABLE
})
@Retention
(
RetentionPolicy
.
SOURCE
)
public @interface
SuppressWarnings
{
String
[]
value
();
}
package
com
.
zy
.
annotation
;
public @interface
Ann03
{
}
属性:接⼝中的抽象⽅法
元注解:⽤于描述注解的注解
oldyang
@xh
:
~
/
Desktop
/
projects
/
test02
/
src
/
com
/
zy
/
annotation$ javac Ann03
.
java
oldyang
@xh
:
~
/
Desktop
/
projects
/
test02
/
src
/
com
/
zy
/
annotation$ javap Ann03
警告
:
⼆进制⽂件
Ann03
包含
com
.
zy
.
annotation
.
Ann03
Compiled from
"Ann03.java"
public interface
com
.
zy
.
annotation
.
Ann03
extends
java
.
lang
.
annotation
.
Annotation
{
}
要求:
1.
属性的返回值类型有下列取值
*
基本数据类型
* String
*
枚举
*
注解
*
以上类型的数组
2.
定义了属性,在使⽤时需要给属性赋值
1.
如果定义属性时,使⽤
default
关键字给属性默认初始化值,则使⽤注解时,可以不进⾏属性的赋值。
2.
如果只有⼀个属性需要赋值,并且属性的名称是
value
,则
value
可以省略,直接定义值即可。
3.
数组赋值时,值使⽤
{}
包裹。如果数组中只有⼀个值,则
{}
可以省略
元注解:⽤于描述注解的注解
*
@Target
:描述注解能够作⽤的位置
*
ElementType
取值:
*
TYPE
:可以作⽤于类上
*
METHOD
:可以作⽤于⽅法上
*
FIELD
:可以作⽤于成员变量上
*
@Retention
:描述注解被保留的阶段
*
Retention
(
保留
)
注解说明
,
这种类型的注解会被保留到那个阶段
.
有三个值
:
1.
RetentionPolicy
.
SOURCE ——
这种类型的
Annotations
只在源代码级别保留
,
编译时就会被忽
略
2.
RetentionPolicy
.
CLASS ——
这种类型的
Annotations
编译时被保留
,
在
class
⽂件中存在
,
但
JVM
将会忽略
示例
:
执⾏的命令
:
3.
RetentionPolicy
.
RUNTIME ——
这种类型的
Annotations
将被
JVM
保留
,
所以他们能在运⾏时
被
JVM
或其他使⽤反射机制的代码所读取和使⽤
.
*
@Retention
(
RetentionPolicy
.
RUNTIME
)
:当前被描述的注解,会保留到
class
字节码⽂件中,并
被
JVM
读取到
,
我们⾃定义的⼀般使⽤这个阶段
*
@Documented
:描述注解是否被抽取到
api
⽂档中
*
@Inherited
:描述注解是否被⼦类继承
import
java
.
lang
.
annotation
.
*
;
//TYPE:
作⽤于类上⾯
@Target
(
value
=
{
ElementType
.
TYPE
,
ElementType
.
METHOD
,
ElementType
.
FIELD
})
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Documented
public @interface
Ann04
{
}
@Ann04
@Ann03
(
name
=
"
⼩灰
"
,
years
=
2022
,
p
=
Person
.
p1
,
ann01
=
@Ann01
)
public class
Test01
{
public static
void
main
(
String
[]
args
) {
Anno2 anno2
=
new
Anno2
();
anno2
.
show1
();
Date date
=
new
Date
();
date
.
getYear
();
}
@Ann04
public
void
show
() {
}
@Ann04
int
a
;
}
javadoc
*
.
java
-
d doc
-
version
-
author
效果
在程序使⽤
(
解析
)
注解:获取注解中定义的属性值
1.
定义注解类
在程序使⽤
(
解析
)
注解:获取注解中定义的属性值
1.
获取注解定义的位置的对象
(
Class
,
Method
,
Field
)
2.
获取指定的注解
*
getAnnotation
(
Class
)
3.
调⽤注解中的抽象⽅法获取配置的属性值
package
com
.
zy
.
annotation
;
import
java
.
lang
.
annotation
.
ElementType
;
import
java
.
lang
.
annotation
.
Retention
;
import
java
.
lang
.
annotation
.
RetentionPolicy
;
import
java
.
lang
.
annotation
.
Target
;
/**
* @author
⼩灰
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
TYPE
)
public @interface
ConfigInfo
{
String
className
();
//
类名
String
methodName
();
//
⽅法名
}
2.
定义测试的类
3.
定义注解使⽤测试的类
5.
案例:简单的测试框架
1.
被测试的类
package
com
.
zy
.
annotation
;
public class
Demo01
{
public
void
show
() {
System
.
out
.
println
(
"
这⾥测试打印的信息
!"
);
}
public
void
show2
(
String
info
) {
System
.
out
.
println
(
"
这⾥测试打印的信息
!"
+
info
);
}
}
package
com
.
zy
.
annotation
;
@ConfigInfo
(
className
=
"com.zy.annotation.Demo01"
,
methodName
=
"show2"
)
public class
Test02
{
public static
void
main
(
String
[]
args
)
throws
Exception
{
//1.
解析注解
//1.1
获取该类的字节码⽂件对象
Class
<
Test02
>
aClass
=
Test02
.
class
;
//2.
获取上边的注解对象
ConfigInfo annotation
=
aClass
.
getAnnotation
(
ConfigInfo
.
class
);
//3.
调⽤注解中定义的⽅法
,
获取返回值
String
className
=
annotation
.
className
();
String
methodName
=
annotation
.
methodName
();
//
初始化
Class aClass1
=
Class
.
forName
(
className
);
aClass1
.
getMethod
(
methodName
,
String
.
class
).
invoke
(
aClass1
.
newInstance
(),
"2020"
);
}
}
package
com
.
zy
.
annotation2
;
//
计算器的类
public class
Calculator
{
//
定义⼀个⽅法
//
加法
2.
注解类
@Check
public
void
add
() {
int
a
=
1
/
0
;
System
.
out
.
println
(
"
这⾥加法
"
);
}
//
减法
@Check
public
void
sub
() {
int
a
=
1
/
0
;
System
.
out
.
println
(
"
这⾥减法
"
);
}
//
乘法
@Check
public
void
mul
() {
String
a
=
null
;
a
.
getBytes
();
System
.
out
.
println
(
"
这⾥乘法
"
);
}
//
除法
@Check
public
void
div
() {
System
.
out
.
println
(
"
这⾥除法
"
);
}
}
package
com
.
zy
.
annotation2
;
import
javax
.
swing
.
*
;
import
java
.
lang
.
annotation
.
ElementType
;
import
java
.
lang
.
annotation
.
Retention
;
import
java
.
lang
.
annotation
.
RetentionPolicy
;
import
java
.
lang
.
annotation
.
Target
;
/**
⽤来检测⽅法是否有异常
* @author
⼩类
*
*/
@Retention
(
RetentionPolicy
.
RUNTIME
)
@Target
(
ElementType
.
METHOD
)
public @interface
Check
{
}
3.
测试框架类
package
com
.
zy
.
annotation2
;
import
java
.
io
.
BufferedWriter
;
import
java
.
io
.
FileWriter
;
import
java
.
io
.
IOException
;
import
java
.
lang
.
reflect
.
InvocationTargetException
;
import
java
.
lang
.
reflect
.
Method
;
import
java
.
util
.
Calendar
;
/**
*
做⼀个简单的测试的框架
* //1.
创建测试的类
* //2.
得到字节码
* //3.
获取所有的⽅法
* //4.
判断是否⽅法上有
Check
注解
* //5.
有就执⾏⽅法
* //6.
捕获异常
*
当
main
⽅法执⾏的时候
,
会⾃动去检测所有的⽅法
(
加了
@check
的⽅法
),
判断是否有异常
,
并把异常记录到⽂件中
*/
public class
TestMethod
{
public static
void
main
(
String
[]
args
)
throws
Exception
{
//
定义异常计数
int
number
=
0
;
//
定义异常的⽂件流
BufferedWriter bufferedWriter
=
new
BufferedWriter
(
new
FileWriter
(
"bug.txt"
,
false
));
//1.
创建测试的类
Calculator calculator
=
new
Calculator
();
//2.
得到字节码
Class aClass
=
calculator
.
getClass
();
//3.
获取所有的⽅法
Method
[]
methods
=
aClass
.
getMethods
();
for
(
Method method
:
methods
) {
//4.
判断是否⽅法上有
Check
注释
if
(
method
.
isAnnotationPresent
(
Check
.
class
)) {
try
{
//5.
有就执⾏⽅法
//6.
捕获异常
method
.
invoke
(
calculator
);
}
catch
(
Exception e
) {
e
.
printStackTrace
();
number
++
;
//
异常加
1
bufferedWriter
.
write
(
method
.
getName
()
+
"
⽅法出异常了
!"
);
bufferedWriter
.
newLine
();
bufferedWriter
.
write
(
"
异常的名称
:"
+
e
.
getCause
().
getClass
());
bufferedWriter
.
newLine
();
bufferedWriter
.
write
(
"
异常的原因
:"
+
e
.
getCause
().
getMessage
());
bufferedWriter
.
newLine
();
bufferedWriter
.
write
(
"----------------------------"
);
bufferedWriter
.
newLine
();
}
}
}
bufferedWriter
.
write
(
"
本次⼀共出现
"
+
number
+
"
次异常
!"
);
bufferedWriter
.
newLine
();
bufferedWriter
.
flush
();
bufferedWriter
.
close
();
}
}