java基础知识之注解、反射(一)

前言

此博客为供个人学习总结备用,如有错误请指正。

正文

Annotation(注解)

java自带的注解包含以下三个:

1.@Override         注解表示重写父类的方法
2.@Deprecated       声明被注解的方法或字段等废弃,不建议使用
3.@SuppressWarnings 抑制所有的警告

其中@Deprecated和@SuppressWarnings注解可以配置多个参数,用来表达不同的对象范围,如@SuppressWarnings({“unchecked”,“unused”})表示抑制警告。
点开SuppressWarnings 注解源代码查看:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();//表示注解定义时传递的参数
}

@SuppressWarnings 注解是使用@interface定义来定义的,而该注解又被java元注解所修饰,元注解表示用来解释注解的注解,常见@Target和@Retention使用:

Target注解表示注解能配置的范围,如:
@Target({TYPE, FIELD, METHOD})表示注解配置范围为type(类型)field(字段)METHOD(方法)

@Retention用于描述注解的生命周期如:@Retention(RetentionPolicy.RUNTIME)
		SOURCE表示在源文件中有效
		CLASS表示在CLASS文件有效
		RUNTIME表示运行时有效,可以被反射机制读取

下面实现一个简单的自定义注解:
首先使用@interface定义注解:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

@Retention(RetentionPolicy.RUNTIME)//运行时有效
@Target(value={FIELD, METHOD, TYPE})//配置了注解的使用范围,字段、方法和类型
public @interface MyAnnotation {
    String[] value();//只有一个值的时候一般命名为value(),且注解传值时可省略value=
    int age() default -1;//不传值时age相当于不存在未定义,不强求传值
    String StudentName() default "小明";//默认值小明
}

然后在类中进行使用:

import java.util.Date;

public class Demo01 {
    //使用自定义注解并传值
    @MyAnnotation(value = {"d","f"}, StudentName = "小兰")
    private int i;

    //@Override注解表示重写父类的方法
    @Override
    public String toString(){
       return i +"";
    }

    //表示废弃,不建议使用
    @Deprecated
    public static void test(){
        System.out.println("test");
    }

    //抑制所有的警告,参数可以配置多个,如:
    //@SuppressWarnings("all")
    @SuppressWarnings({"all","unused"})
    public static void main(String[] args) {
        Date date = new Date();
        test();
    }
}

可能到这里有些迷惑,自定义注解然后呢,有个毛用啊。这就要涉及到反射了,在反射中取到注解注入的信息,能够减少开发的工作量。下面再举个注解的例子:
自定义两个注解,Table和Field用来对数据库表名和字段产生对应关系。
SxtTable注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SxtTable {
    String value();//用来接收对应数据库表名
}

SxtField注解:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SxtField {
    String columnName();//对应表字段名
    String type();//字段类型
    int length();//长度
}

接下来定义Student类,包括学号、姓名和年龄三个属性,并生成get、set方法:

@SxtTable("tb_student")
public class SxtStudent {

    public SxtStudent() {
    }

    public SxtStudent(int id) {
        this.id = id;
    }

    @SxtField(columnName = "id", type = "int", length = 10)
    private int id;
    @SxtField(columnName = "sname", type = "nvarchar", length = 50)
    private String StudentName;
    @SxtField(columnName = "age", type = "int", length = 10)
    private int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getStudentName() {
        return StudentName;
    }

    public void setStudentName(String studentName) {
        StudentName = studentName;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

那么现在已经将学生类通过注解对应到数据库了,由@SxtTable(“tb_student”)知对应表名tb_student,由@SxtField看到学生类的各属性分别对应表字段。
接下来就可以通过反射读取注解进行相应的操作了,那就有可能插入学生信息到表就像mybatis插入数据那么方便了,注解的价值就得以体现。
注解怎么通过反射进行获取?

反射

反射暂时也说不出个所以然,来看看大概怎么使用吧:

//加载类对象
Class clazz = Class.forName("annotation.testAnnotation.SxtStudent");
System.out.println(clazz);
//获取类的属性
Field f01 = clazz.getField("id");//只能获取到公有的属性
System.out.println(f01);
Field f02 = clazz.getDeclaredField("id");//获取所有声明的属性
System.out.println(f02);
//获取到所以属性
Field[] fields01 = clazz.getFields();//同样只能获取公开的属性
Field[] fields = clazz.getDeclaredFields();//获取所有声明的属性
for (Field temp : fields) {
    System.out.println("属性:" + temp);
}
//获得类的方法,和属性类似
//第二个参数传递方法参数类型,用以区分当重写方法名字相同的情况
Method m01 = clazz.getDeclaredMethod("setAge", int.class);

//获得构造器信息
Constructor[] constructors = clazz.getDeclaredConstructors();
//获得无参构造器
Constructor constructor = clazz.getDeclaredConstructor(null);
//获取参数为int的构造器
Constructor constructor1 = clazz.getDeclaredConstructor(int.class);
System.out.println(constructor);

//调用了SxtStudent无参的构造函数,
// 注意如果类中实现了有参构造器,调用方法会有异常,一般保留无参的构造函数
SxtStudent student = clazz.newInstance();
System.out.println(student);

//动态使用构造器
Constructor<SxtStudent> c =
        clazz.getDeclaredConstructor(int.class);
SxtStudent s1 = c.newInstance(3);
System.out.println(s1.getId());

//使用方法
SxtStudent s2 = clazz.newInstance();
Method m = clazz.getDeclaredMethod("setId", int.class);
m.invoke(s2, 5); //等价于s2.setId(7);
System.out.println(s2.getId());

//直接设置属性的值
SxtStudent s3 = clazz.newInstance();
Field f = clazz.getDeclaredField("id");
f.setAccessible(true);//表示不做安全性检查,可以提交速度,看情况使用
f.set(s3,9);//跳过安全性检查才能直接设置私有属性的值
System.out.println(s3.getId());

//------------------反射获取注解--------------------------
//获得类的所有有效注解
Class clazz = Class.forName("annotation.testAnnotation.SxtStudent");
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation: annotations){
    System.out.println(annotation);
}
//获得指定注解
SxtTable table = (SxtTable) clazz.getAnnotation(SxtTable.class);
System.out.println(table.value());
//获得类属性的注解
Field f = clazz.getDeclaredField("id");
SxtField SxtField = f.getAnnotation(SxtField.class);
System.out.println(SxtField.columnName() + "---" + 
						SxtField.type() + "---" + SxtField.length());

基础的使用大致就是这样,再说明一下注意点:
Class.forName(path) JVM会加载一个类的Class对象,并且同一个类只会有一个Class对象,多次加载的对象相同。
反射会影响程序性能,让程序变慢。setAccessible(true);//表示不做安全性检查,能提高反射的效率,利弊需自己衡量,在不需要安全检查的时候设置true能大大提高效率。

System.out.println("sdfj".getClass());
//"相同类型加载的类是一样的,JVM只会加载一个实例"
System.out.println("jdksll".getClass() == "sdfj".getClass());
//不同空间的Class实例不同
int[] j = {1,2,4};
int[][] k = new int[2][3];
System.out.println(j.getClass().hashCode() + "|" + k.getClass().hashCode());

java反射还能够获取到泛型,感兴趣可以自行搜索。
java基础知识之注解、反射(二)

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值