java-注解

注解

概念

在这里插入图片描述

注解可以理解为注释的一种:

我们常说的注释就是在代码中的一些解释,纯粹的为了增强代码的可读性。编译器不会编译这些注释。

注解在程序中是有一定的意义,有一些注解会一致持续到程序运行都是有效的。

JDK已经提供的注解:

1.@Override 标记一个方法是重写的父类的方法

在这里插入图片描述

2.@Deprecated 标记一个方法是过时方法,不建议使用的方法

在这里插入图片描述

3.@SuppressWarnings 消除警告的注解

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdcZAQH8-1632310432047)(assets/1599010318241.png)]

4.@SafeVarargs 消除对污染警告
在声明具有模糊类型(比如:泛型)的可变参数的构造函数或方法时,Java编译器会报unchecked警告。鉴于这些情况,如果程序员断定声明的构造函数和方法的主体不会对其varargs参数执行潜在的不安全的操作,可使用@SafeVarargs进行标记,这样的话,Java编译器就不会报unchecked警告。
5.@FunctionalInterface 函数式接口

注解都是@Xxxxxxx。

注解可以注解类,局部变量,成员变量,方法,参数

注解可以在源码阶段,编译阶段,运行阶段生效

自定义注解

了解几个JKD的注解(源注解):

@Target
在这里插入图片描述

@Target使用来注解其他的注解的,主要是表示其他的注解可以使用的位置(目标)。

@Retention
在这里插入图片描述

自己写一个自定义注解:

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午9:44:58
 */
//@Target   //St这个注解可以注解的位置(类,接口,枚举,注解,方法,构造方法,变量,参数等等)
//@Retention  //表示St这个注解的存活范围(源码阶段,编译阶段,运行阶段)
public @interface St {
}

使用:

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午9:49:27
 */
@St
public class Test {
	@St
	public Test() {}
	@St
	private String name;
	@St
	public static void main(@St String[] args) {
		@St
		int age;
	}
}

@Target注解

@Target标记一个注解的可注解位置。

有几个值:

TYPE:java中的四大类型(类,枚举,接口,注解)

FIELD:成员变量

METHOD:成员方法

PARAMETER:方法的参数

CONSTRUCTOR:构造方法

LOCAL_VARIABLE:局部变量

ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE

如果我们自定义的注解不适用@Target注解,那么我们的注解可以写在任何为止。

案例:
在这里插入图片描述

除过成员变量之外的其他位置的注解全部报错:

可以在Target中同时多指定几个位置:
在这里插入图片描述

@Retention注解

标注一个注解的存活范围:

SOURCE:源码阶段,

CLASS:编译阶段,

RUNTIME:运行阶段
在这里插入图片描述

自定义注解的属性

注解中是可以写属性的,属性的写法和类的写法略有不同。

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午10:12:28
 */
public @interface StValue {
	//注解的自定义的属性(没有setget方法)
	String name();
	int age();
	String tel();
}

注解的属性都是public修饰的。

注解中属性的写法 类型 属性名();没有setter和getter方法。

注解中属性的赋值:

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午10:14:53
 */
@StValue(name="卡卡西",age=28,tel="13813813838")
public class Demo2 {	
}

如果注解中申明一个属性,并且这个属性没有默认值,则使用注解时必须给这个属性赋值。

如果有多个属性需要赋值,可以使用“,”隔开进行赋值。赋值的方式和java中的一致。

注解中的属性也可以有默认值:

public @interface StValue {
	//注解的自定义的属性(没有setget方法)
	String name();
	int age() default 18; //有默认值的属性
	String tel() default "110";//有默认值的属性
}

如果属性有默认值,那么在使用这个注解的时候可以选择性的赋值。

	//这里的age就使用了默认值
	@StValue(name="佐助",tel="120")
	private String name;

注解中的属性也可以是数组

public @interface StValue {
	//注解的自定义的属性(没有setget方法)
	String name();
	int age() default 18; //有默认值的属性
	String tel() default "110";//有默认值的属性
	String [] email();//数组属性
}

给数组的属性赋值,可以使用“{}”。 如果只有一个值就可以省略“{}”

	//给数组形式的属性赋值(赋多个值)
	@StValue(name="年龄",email={"abc@12.com","def@345.com"})
	private int age;
	//给数组属性赋值(只有一个值)
	@StValue(name="电话",email="st@st.com")
	private String tel;

特殊的value属性:value属性是注解中的一个非常特殊的属性,可以是任何类型,可有默认值或者没有默认值。

public @interface StNames {
	//value属性
	String value();
}

使用注解,并且给value属性赋值,不需要写value=""

@StNames("demo3")
public class Demo3 {
}

这种情况只限于只有一个value属性赋值的时候使用。

如果出现了多个属性需要赋值,则需要写value=""

public @interface StNames {
	//value属性
	String value();
	int age();//其他需要赋值的属性
}

使用:

@StNames(value="demo3",age=18)
public class Demo3 {
}

tips:注解的属性类型可以是任何java类型。
在这里插入图片描述

使用:
在这里插入图片描述

使用反射机制获取注解

Class类中有一些可以获取一个类的注解的API:

A getAnnotation(Class<A> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。
Annotation[] getAnnotations()
返回此元素上存在的所有注释(包含从其他地方继承的注解)。

Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注释。

除过Class类之外其他的几个反射相关的类都有getAnnotation和getDeclaredAnnotations方法。

Field,Method,Constructor等。

案例:

tips:如果希望通过反射获取到注解,则这个的存活范围必须是RUNTIME。

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午10:42:32
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface DefValue {
	String value();
	int age();
}
/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午10:42:50
 */
public class Test {
	public static void main(String[] args) {
		//通过Class获取类上方的注解
		Class clz = Person.class;
		Annotation annotation = clz.getAnnotation(DefValue.class);
		System.out.println(annotation);
	}
}
@DefValue(value="PERSON",age=45)
class Person{}

通过getAnnotation方法获取注解,参数是注解的本身的class对象,返回值(没有泛型)是Annotation接口。默认所有的注解都继承自Annotation接口。

获取注解的属性值:
在这里插入图片描述

其他的几个获取注解的API

		//获取类上方的所有注解
		clz = Student.class;
		//获取自己申明的注解以及继承的注解。  当然继承的注解必须有@Inherited源注解
		Annotation[] ans = clz.getAnnotations();
		for (int i = 0; i < ans.length; i++) {
			System.out.println(ans[i]);
		}
		//获取自己申明的注解
		System.out.println("----------");
		ans = clz.getDeclaredAnnotations();
		for (int i = 0; i < ans.length; i++) {
			System.out.println(ans[i]);
		}

案例

我们可以在配置文件中给对象的属性赋初始值。使用注解和放射实现。

[1]准备一个配置文件config.txt

内容如下:

brand=路基亚
cost=500000

[2]在程序启动的时候将文件中的内容读取到缓存中,准备一个Data类

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午11:12:04
 */
public class Data {
	public static Map<String,String> datas = new HashMap<String,String>();
	static {
		FileReader reader = null;
		BufferedReader bufReader = null;
		try {
			reader = new FileReader("config.txt");
			bufReader = new BufferedReader(reader);
			String line = null;
			while((line = bufReader.readLine())!=null) {
				String[] infos = line.split("=");
				datas.put(infos[0], infos[1]);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			try {
				if(reader!=null)
					reader.close();
				if(bufReader!=null)
					bufReader.close();
			} catch (Exception e2) {
				e2.printStackTrace();
			}
		}
	}
}

[3]准备一个注解 @Value

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午11:16:06
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Value {
	//要读取的配置文件中的属性的名字
	String value();
}

[4]自定义一个类,使用@Value配置值
在这里插入图片描述

[5]在Car中添加一个非静态代码块,在非静态代码块中初始化这些属性值

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午11:09:26
 */
public class Car {
	@Value("brand")//将配置文件中的name为brand的值赋值给这个属性
	private String brand;
	@Value("cost")//将配置文件中的cost的值赋值给cost
	private int cost;
	private String addr;
	//非静态代码块,初始化属性值
	{
		//获取当前类的Class
		Class clz = this.getClass();
		//获取所有的域
		Field[] fields = clz.getDeclaredFields();
		//遍历赋值
		for (Field field : fields) {
			//设置这个域为可见
			field.setAccessible(true);
			//获取域上方的value注解
			Value annotation = field.getDeclaredAnnotation(Value.class);
			if(annotation!=null) {//有@Value注解
				//取出@Value中的属性值
				String key = annotation.value();
				//通过key从map中取出值
				String value = Data.datas.get(key);
				//获取属性的类型
				Class typeClz = field.getType();
				try {
					if(typeClz==int.class) {
					//将取出的value赋值给当前的属性Field
						field.set(this, Integer.parseInt(value));
					}else if(typeClz == String.class) {
						field.set(this, value);
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
	
	@Override
	public String toString() {
		return "Car [brand=" + brand + ", cost=" + cost + "]";
	}
	//setter和getter省略
}

测试:

/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午11:25:36
 */
public class Test {
	public static void main(String[] args) {
		Car car = new Car();
		System.out.println(car);
	}
}

{
field.set(this, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}

@Override
public String toString() {
	return "Car [brand=" + brand + ", cost=" + cost + "]";
}
//setter和getter省略

}


测试:

```java
/**
 * @author 戴着假发的程序员
 * @TODO 
 * @organization 飞虎队
 * 2020年9月2日 上午11:25:36
 */
public class Test {
	public static void main(String[] args) {
		Car car = new Car();
		System.out.println(car);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

戴着假发的程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值