java 注解入门(一)
我们都知道注释是为了解释代码,给程序员看的,那注解是干嘛的呢? 注解相当于一种标记,给计算机看的,在程序中加了注解就等于为程序打上了某种标记。以后,javac编译器,开发工具和其他程序可以利用反射了解你的类及各种元素上有无何种标记,看你有什么标记,就去干相应的事。注解可以加在包,类,字段,方法,方法的参数及局部变量上。在一定程度上,就是起配置文件作用。
要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。
元注解:
元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
1.@Target,
2.@Retention,
3.@Documented,
4.@Inherited
@Target:
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
取值(ElementType)有:
1.ElementType.CONSTRUCTOR: 构造器声明
2.ElementType.FIELD: 成员变量、对象、属性
3.ElementType.LOCAL_VARIABLE: 局部变量声明
4.ElementType.METHOD: 方法声明
5.ElementType.PACKAGE: 包声明
6.ElementType.PARAMETER: 参数声明
7.ElementType.TYPE: 类、接口或enum声明
/**
* Project: 自定义注解
* Created: Administrator
*/
//表明该注解用于属性上
@Target(ElementType.FIELD)
public @interface AnnoteTest {
String value();
}
@Retention:
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
取值(RetentionPoicy)有:
1.RetentionPoicy.SOURCE:在源文件中有效(即源文件保留)
2.RetentionPoicy.CLASS:在class文件中有效(即class保留)
3.RetentionPoicy.RUNTIME:在运行时有效(即运行时保留)
/**
* Project: 自定义注解
* Created: Administrator
*/
//表明该注解在运行时有效
@Retention(RetentionPoicy.RUNTIME)
public @interface AnnoteTest {
String value();
}
@Documented:
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
@Inherited:
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第三,如果只有一个参数成员,最好把参数名称设为”value”,后加小括号.例:下面的例子FruitName注解就只有一个参数成员。
注解元素的默认值:
注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。
以代码说话: 我们根据实体类属性上的注解值对应XML文件中的配置值初始化属性。
/**
* Project: 自定义注解
* Created: Administrator
*
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotaStr {
String id();
}
<!-- xml文件的配置值-->
<base>
<node id="10">二蛋</node>
<node id="11">二丫</node>
<node id="12">二球</node>
<node id="13">二货</node>
<node id="14">二逼</node>
</base>
public class Entry1 {
@AnnotaStr(id="10")
private String str0;
@AnnotaStr(id="11")
private String str1;
@AnnotaStr(id="12")
private String str2;
@AnnotaStr(id="13")
private String str3;
@AnnotaStr(id="14")
private String str4;
private Map<String,String> xmlMap=new HashMap<>();
//实体类属性的get()set()方法在这里就不写了
public void setXML(){
try {
//使用XmlPull解析解析XML文件,并把xml里的数据放在实体类的xmlMap属性里。
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser pullParser = factory.newPullParser();
pullParser.setInput(new FileReader("res/test.xml"));
int type;
while ((type = pullParser.next()) != XmlPullParser.END_DOCUMENT) {
switch (type){
case XmlPullParser.START_TAG:
if("node".equals(pullParser.getName())){
String key=pullParser.getAttributeValue(null,"id");
String value=pullParser.nextText().trim();
xmlMap.put(key,value);
}
break;
}
}
} catch (XmlPullParserException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
public class Utils {
public static void initStr(Entry1 entry){
try {
//利用反射拿到实体类的属性
Field[] fields = entry.getClass().getDeclaredFields();
for(Field field : fields){
//遍历实体类xmlMap属性(除了xmlMap)
if(!"xmlMap".equals(field.getName())) {
//拿到属性的注解值,根据注解值取得map中的value赋给该属性
String id=field.getAnnotation(AnnotaStr.class).id();
if(id!=null){
field.setAccessible(true);
field.set(entry, entry.getXmlMap().get(id));
}
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
public class Test1 {
public static void main(String[] args) {
Entry1 entry1 = new Entry1();
entry1.setXML();
System.out.println(entry1.getXmlMap());
Utils.initStr(entry1);
System.out.println(entry1);
}
}
通过上面的代码我们就可以根据注解对实体类进行恢复初始化操作,一般我们对实体类进行了修改,就很难恢复最开始的默认化数据。