Java注解的使用
- 学前须知
- 元注解
- java.lang 中的注解
- java.lang.annotation中的注解
- 注解的定义和传参
- 反射
- 五种获取Class对象的方法
- 反射的使用
- 反射创建对象
- 反射操作注解
- 练习
学前须知
具有Java基础知识,包括JVM类加载,反射等基础。
反射是框架的前提,通过注解和反射机制,java实现了动态语言的一部分特性
元注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
java.lang 中的注解
@Override - 检查该方法是否是重写方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
@Deprecated - 标记过时方法。如果使用该方法,会报编译警告。有这个注解的方法不建议使用
@SuppressWarnings - 指示编译器去忽略注解中声明的警告。去除告警波浪线,专治强迫症。
java.lang.annotation中的注解
@Target - 注解使用的范围,比如包,类,方法,字段
@Retention - 表示需要在什么级别保存该注释信息,用于描述注解的生命周期(一般都是RUNTIME级别)
@Documented - 标记这些注解是否包含在javadoc中
@Inherited - 说明子类可以继承父类的注解
// 使用注解
@MyAnnotation
public class Test01 {
}
// 定义一个注解
// 注解可以用在哪些地方
@Target(value = {ElementType.METHOD,ElementType.TYPE})
// 注解在什么地方有效,一般是Runtime
@Retention(value = RetentionPolicy.RUNTIME)
// 将注解生成在JavaDoc中
@Documented
// 子类继承父类注解
@Inherited
// 定义一个注解
@interface MyAnnotation{
}
注解的定义和传参
// 无默认值的注解
@MyAnnotation2(name = "qwer")
public class Test02 {
}
// 参数默认为value,且有默认值的注解
@MyAnnotation3
class Test02_2 {
}
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
// 默认值名是value
String value() default "";
// 定义变量后面要加()
String name();
// 可以给变量赋默认值
int age() default 18;
}
@Target(value = {ElementType.TYPE,ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation3{
// 默认值名是value
String value() default "默认值";
}
反射
Reflection (反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一 个类只有
一个Class对象), 这个对象就包含了完整的类的结构信息。我们可以通过这个对
象看到类的结构。这个对象就像一面镜子, 透过这个镜子看到类的结构,所以,
我们形象的称之为:反射
五种获取Class对象的方法
反射的使用
public class Test03 {
public static void main(String[] args) throws Exception{
Class c1 = Class.forName("Test");
Method methods[] = c1.getMethods();
System.out.println("获取到method[0]方法名 "+methods[0].getName());
// 注意!,获取类的方法顺序与类定义方法的顺序不一定一致 多次执行结果会有所不同
// 通过反射,调用空参方法和有参方法
methods[0].invoke(new Test(),null);
methods[1].invoke(new Test(),"aaa"); //String.Class
System.out.println("============================");
Class c2 = Class.forName("Person");
Method method1 = c2.getMethod("setName",String.class);
// 类加载的理解,我set参数李四,最后打出来还是张三,参考图片理解
method1.invoke(new Person(),"李四");
Method method2 = c2.getMethod("getName",null);
System.out.println(method2.invoke(new Person()));
// 获取字段
Field f1 = c2.getDeclaredField("name");
Field f2[] = c2.getFields();//获取权限为public的参数
Field f3[] = c2.getDeclaredFields();//获取所有的参数
System.out.println(f1);
System.out.println("============================");
for (int i = 0; i < f3.length ; i++) {
System.out.println(f3[i]);
}
}
}
class Test{
public void fun1(){
System.out.println("method f1 running");
}
public void fun2(String str){
System.out.println("method f1 running args:"+str);
}
}
class Person{
public String name = "张三";
private int age = 18;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
参考图片
反射创建对象
public class Test04 {
public static void main(String[] args) throws Exception{
Class c1 = Class.forName("User");
// 无参的构造器,构造方法
Constructor constructor1 = c1.getConstructor();
User user1 = (User)constructor1.newInstance();
System.out.println(user1.toString());
// 有参的构造器,构造方法
Constructor constructor2 = c1.getConstructor(String.class,String.class);
//constructor2.setAccessible(true);//关闭权限检查,提升性能
User user2 = (User)constructor2.newInstance("张三","123456");
System.out.println(user2.toString());
}
}
class User{
public String username;
public String password;
public String getUsername() {
return username;
}
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public void setUsername(String username) {
this.username = username;
}
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
}
反射操作注解
public class Test05 {
public static void main(String[] args) throws Exception{
Class c1 = Class.forName("MyUser");
Annotation annotations[] = c1.getAnnotations();
TableUser userAnno = (TableUser) c1.getAnnotation(TableUser.class);
String value = userAnno.value();
System.out.printf(value);
// 获得类指定的注解
Field id = c1.getDeclaredField("id");
FieldUser fieldAnno = (FieldUser) id.getAnnotation(FieldUser.class);
String columName = fieldAnno.columName();
String type = fieldAnno.type();
int length = fieldAnno.length();
System.out.printf("%s %s %d",columName,type,length);
}
}
@TableUser("user")
class MyUser{
@FieldUser(columName = "db_id",type = "varchar",length = 64)
public String id;
@FieldUser(columName = "db_age",type = "number",length = 3)
public int age;
}
// 类的注解
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
@interface TableUser{
String value();
}
// 属性的注解
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface FieldUser{
String columName();
String type();
int length();
}
练习
注解操作数据库示例
效果如图
项目地址:
https://github.com/13884566853/Java-test/tree/main/annotation-test 补充
从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
@FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
@Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。