Java5开始,Java开始对元数据的支持,也就是annotation(注解/标签)
元数据:metadata:描述数据的数据:
所有的Annotation都是java.lang.annotation.Annotation接口的子接口,所以Annotation是一种特殊的接口(枚举也是特殊的类)
枚举:所有的枚举类型都是java.lang.Enum类的子类。--->枚举是一种特殊的类。
注解:所有的注解都是java.lang.annotation.Annotation接口的子接口,注解是一种特殊的接口。
使用注解:
注意:注解本身不具有任何功能,得提供第三方的程序来赋予它功能。
使用注解有三方程序参与:
1、首先必须存在一个注解类;
2、其次必须存在被贴的程序元素;
3、必须有第三方的程序来赋予注解特殊的功能(反射操作)。
在Java中,自带有5个注解:(Java5出现3个,Java7出现1个,Java8出现1个):
@Override 限定子类是否覆写父类方法
@Deprecated 标记已过时,过时的方法/类不推荐使用
@SuppressWarings 抑制编译器发出的警告,仅仅是抑制警告,问题依然存在
@SuppressWarings(value="all")
@safeVarargs 抑制堆污染警告(Java7开始出现的)
@FunctionalInterface Java8出现,表示函数式接口,只允许该接口中只有一个抽象方法。如果一个接口中就只有一个抽象方法,也可以不使用注解。可以运用函数式编程(lambda语法)。
Java5才开始出现注解,才开始有@Deprecated注解,但是java.util.Date类中在JDK1.1的时候很多方法就过时了:
在Java5之前标记某一个方法过时,使用文档注释。
注解:用来贴在类,方法,构造器,字段,参数等之上,用于给被贴的程序元素赋予一定的功能。
元注解:在注解定义的时候,必须使用元注解来标注,元注解的注解。
@Retention:决定了注解可以保持在哪一个时期,一共三个时期,都封装在RetentionPolicy枚举类中:
SOURCE:该注解在编译时期就会丢弃,不会存在于字节码文件中,只能存在于源文件中;
CLASS:该注解可以存在源文件和字节码文件中,但是一旦加载进JVM,就丢失;
RUNTIME:该注解可以存在源文件,字节码,JVM中。
自定义的注解类,都是要RUNTIME,因为我们需要在运行时期通过反射赋予注解特殊功能。
@Target:决定了注解可以贴在哪些成员元素之上。可以贴的成员元素都很多,都封装在ElementType枚举类中。
ElementType.ANNOTATION_TYPE 只能修饰注释类型声明
ElementType.CONSTRUCTOR 只能修饰构造方法声明
ElementType.FIELD 只能修饰字段声明(包括枚举常量)
ElementType.LOCAL_VARIABLE 只能修饰局部变量声明
ElementType.METHOD 只能修饰方法声明
ElementType.PACKAGE 只能修饰包声明
ElementType.PARAMETER 只能修饰参数声明
ElementType.TYPE 只能修饰类、接口(包括注释类型)或枚举声明
@Documentd:使用@Documentd标注的标签会保存字API文档中。
@Inherited:@Inherited标注的标签可以被子类所继承。
常用的API:
Annotation getAnnotation(Class annotationClass):判断当前类、方法、字段上是否拥有指定的注解,若有,则返回当前对象,若没有返回null;
Annotation[] getAnnotations():返回此元素上存在的所有注释。
Gender需要设置成public:
赋予特殊功能得类:
运行结果:
新建一个注解类:
MainActivity.java中:
这里就不演示运行结果了,大家运行过后可能有点感觉像ButterKnife,不过ButterKnife比这个强大多了。
元数据:metadata:描述数据的数据:
所有的Annotation都是java.lang.annotation.Annotation接口的子接口,所以Annotation是一种特殊的接口(枚举也是特殊的类)
枚举:所有的枚举类型都是java.lang.Enum类的子类。--->枚举是一种特殊的类。
注解:所有的注解都是java.lang.annotation.Annotation接口的子接口,注解是一种特殊的接口。
使用注解:
注意:注解本身不具有任何功能,得提供第三方的程序来赋予它功能。
使用注解有三方程序参与:
1、首先必须存在一个注解类;
2、其次必须存在被贴的程序元素;
3、必须有第三方的程序来赋予注解特殊的功能(反射操作)。
在Java中,自带有5个注解:(Java5出现3个,Java7出现1个,Java8出现1个):
@Override 限定子类是否覆写父类方法
@Deprecated 标记已过时,过时的方法/类不推荐使用
@SuppressWarings 抑制编译器发出的警告,仅仅是抑制警告,问题依然存在
@SuppressWarings(value="all")
@safeVarargs 抑制堆污染警告(Java7开始出现的)
@FunctionalInterface Java8出现,表示函数式接口,只允许该接口中只有一个抽象方法。如果一个接口中就只有一个抽象方法,也可以不使用注解。可以运用函数式编程(lambda语法)。
Java5才开始出现注解,才开始有@Deprecated注解,但是java.util.Date类中在JDK1.1的时候很多方法就过时了:
在Java5之前标记某一个方法过时,使用文档注释。
/**
* Created by Layne_Yao on 2017-8-5 上午9:51:42.
* CSDN:http://blog.csdn.net/Jsagacity
*/
public class AnnotationDemo {
//从Java5开始
@Deprecated
public void annotation1() {
}
//在Java5之前
/**
* @deprecated
*/
public void annotation2() {
}
public static void main(String[] args) {
}
}
注解:用来贴在类,方法,构造器,字段,参数等之上,用于给被贴的程序元素赋予一定的功能。
元注解:在注解定义的时候,必须使用元注解来标注,元注解的注解。
@Retention:决定了注解可以保持在哪一个时期,一共三个时期,都封装在RetentionPolicy枚举类中:
SOURCE:该注解在编译时期就会丢弃,不会存在于字节码文件中,只能存在于源文件中;
CLASS:该注解可以存在源文件和字节码文件中,但是一旦加载进JVM,就丢失;
RUNTIME:该注解可以存在源文件,字节码,JVM中。
自定义的注解类,都是要RUNTIME,因为我们需要在运行时期通过反射赋予注解特殊功能。
@Target:决定了注解可以贴在哪些成员元素之上。可以贴的成员元素都很多,都封装在ElementType枚举类中。
ElementType.ANNOTATION_TYPE 只能修饰注释类型声明
ElementType.CONSTRUCTOR 只能修饰构造方法声明
ElementType.FIELD 只能修饰字段声明(包括枚举常量)
ElementType.LOCAL_VARIABLE 只能修饰局部变量声明
ElementType.METHOD 只能修饰方法声明
ElementType.PACKAGE 只能修饰包声明
ElementType.PARAMETER 只能修饰参数声明
ElementType.TYPE 只能修饰类、接口(包括注释类型)或枚举声明
@Documentd:使用@Documentd标注的标签会保存字API文档中。
@Inherited:@Inherited标注的标签可以被子类所继承。
常用的API:
Annotation getAnnotation(Class annotationClass):判断当前类、方法、字段上是否拥有指定的注解,若有,则返回当前对象,若没有返回null;
Annotation[] getAnnotations():返回此元素上存在的所有注释。
boolean isAnnotationPresent(Class annotationClass):如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
注解类:
//定义注解
@Target(ElementType.TYPE)//只能修饰类、接口(包括注释类型)或枚举声明
@Retention(RetentionPolicy.RUNTIME)//该注解可以存在源文件,字节码,JVM中。
public @interface INFO {
//注解是特殊的接口,接口中有抽象方法,在注解八抽象方法称为属性
String username();
int age() default 20;//default是设置默认值
String[] hobby();
Gender sex() default Gender.NONE;
}
Gender需要设置成public:
/**
* Created by Layne_Yao on 2017-8-5 上午11:11:03.
* CSDN:http://blog.csdn.net/Jsagacity
*/
public enum Gender{
BOY,GIRL,NONE;
}
赋予特殊功能得类:
/**
* Created by Layne_Yao on 2017-8-5 上午9:51:42.
* CSDN:http://blog.csdn.net/Jsagacity
*/
// 被贴程序元素
@INFO(username = "Layne", age = 18, sex = Gender.BOY, hobby = { "Java",
"Android", "C++" })
class User {
@Deprecated
public void doWork() {
}
}
// 赋予注解特殊功能得
public class AnnotationDemo1 {
public static void main(String[] args) throws Exception {
// 获取Person类上的VIP注解中的信息
Class cls = User.class;
// 获取Person类上所有的注解
Annotation[] as = cls.getAnnotations();
// 判断Person类上是否有VIP注解
boolean isPresent = cls.isAnnotationPresent(INFO.class);
if (isPresent) {
// 取出Person类上的注解
Annotation a = cls.getAnnotation(INFO.class);
// 获取VIP注解中的属性值(调用VIP的抽象方法)
INFO vip = (INFO) a;
System.out.println(vip.username());
System.out.println(vip.age());
System.out.println(vip.sex());
}
// 需求:获取doWork方法上的Deprecated注解
// 1:获取doWork方法所在类的字节码文件
Class doWorkCls = User.class;
// 2:获取doWork方法的Method对象
Method m = doWorkCls.getMethod("doWork");
System.out.println(m);
// 3:获取当前方法上的注解
Deprecated depre = m.getAnnotation(Deprecated.class);
System.out.println(depre);
}
}
运行结果:
上面程序并没有赋予注解功能。
接下来新建一个Android项目,布局文件里面添加两个控件:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.annomationdemo.MainActivity" >
<TextView
android:id="@+id/tv_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="180dp"
android:text="@string/hello_world" />
<Button
android:id="@+id/bt_show"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Button" />
</RelativeLayout>
新建一个注解类:
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 getViewTo {
int value() default -1;
}
MainActivity.java中:
public class MainActivity extends ActionBarActivity {
@getViewTo(R.id.tv_show)
private TextView tv_show;
@getViewTo(R.id.bt_show)
private Button bt_show;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//通过注解生成View
getAllAnnomationView();
bt_show.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
tv_show.setText("注解获取成功");
}
});
}
/**
* 解析注解,获取控件
*/
private void getAllAnnomationView() {
//获取成员变量
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
try {
//判断注解是否为空
if(field.getAnnotations()!=null){
//确定注解类型
if(field.isAnnotationPresent(getViewTo.class)){
//允许修改反射属性
field.setAccessible(true);
getViewTo getViewTo = field.getAnnotation(getViewTo.class);
//通过findViewById将注解的id,找到View并注入成员变量中
field.set(this, findViewById(getViewTo.value()));
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
}
}
}
这里就不演示运行结果了,大家运行过后可能有点感觉像ButterKnife,不过ButterKnife比这个强大多了。