註解

我們爲什麼要學習註解?它可以替代配置文件
註解的使用:
    分如下三步來學習!!!
    一:定義註解類(一般都是框架乾的)
    二:使用註解   (開發人員!)
    三:讀取註解  (一般都是框架乾的:因爲註解最終是代替配置文件,而配置文件最終是要被讀取的!)
    注:註解也是個類,所有的註解都是Annotation的實現類


  一:定義註解類
1.1 定義註解類,那麼怎麼定義呢?

@interface xxx{

}

1.2 定義註解裏面的屬性

@MyAnno1
interface Test2{
	//裏面只存在屬性,當然這裏屬性的格式比較特殊,後面又加個()
	String name();
	int age() default 22;
}

1.3注意:
a.定義屬性時還可以指定默認值,就像上面的age屬性一樣
b.在註解中定義完屬性後,那麼使用註解的時候必須爲註解中的屬性賦值,否則會報錯!(有默認值的可以除外)
c.名爲value屬性的特權

public @interface MyAnno {

	String value();
	int age() default 22;
}

@MyAnno(value = "hello")
class Demo{
	
}

//如果只寫一個屬性的話,那麼value可以省掉
@MyAnno("hello")
class Demo2{
	
}

d.註解中屬性的類型有限制!!,只能是如下幾種!!!

	8種基本類型
	String
	Enum
	Class
	註解類型
	以上類型的一維數組類型【就我說的這幾種,沒別的了】 
        注:當給數組類型的屬性賦值時,假如數組元素的個數爲1時,此時可以不寫{}

e.使用註解併爲註解裏面的屬性賦值! 

//使用註解,注意點【爲註解的屬性賦值時,註解類型和數組的寫法需要注意一下】
@MyAnno1(
	a=22,
	b="wzj",
	c=MyEnum.APPLE,
	d=String.class,
	e=@MyAnno2(city = "zhuzhou"),
	f= {1,2,3}
)
class Test{
	
}


//註解中屬性的類型可以有哪些!
public @interface MyAnno1 {

	int a(); //8種基本數據類型
	String b();//Stirng
	MyEnum c(); //枚舉
	Class d(); //Class類型
	MyAnno2 e();//註解類型
	int[] f(); //以上的一維數組類型!
}

@interface MyAnno2{
	String city();
	String address() default "youxian";
}

enum MyEnum{
	APPLE,PEAR
}

 

  二:使用註解   (開發人員!)
  如上註解已經定義好了, 那麼我們可以在類的哪些地方使用呢?(也就是註解的作用目標)
  註解的作用目標

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

由上可以知道:註解幾乎可以在類的任何地方使用【連局部變量上都行!!】

2.1註解的作用目標限定:@Target
只時候就可以請出@Target註解了

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
    //這時重寫的那個註解的源碼,我們可以看到Target裏面的屬性類型
    //既不是8種基本數據類型,也不是Class和String,所以只能是枚舉了,
    //而且不用寫屬性名,說明@Target註解裏面有value屬性,而且可能只有一個
}

那麼我現在不想讓它在這麼多的目標上可以使用,假如我只想讓它在類上那麼這麼辦? 

@Target(ElementType.TYPE)
public @interface MyAnno {

	String value();
	int age() default 22;
}

@MyAnno(value = "hello")
class Demo{
	
	@MyAnno(value = "hello") 
	public void method() {} //這個地方會報錯,因爲我限定了這個註解只能在類上使用!
}

2.2:保留策略 @Retention(RetentionPolicy.SOURCE/CLASS/RUNTIME)
源代碼文件(SOURCE):註解只在源代碼中存在,當編譯時就被忽略了
字節碼文件(CLASS):註解在源代碼中存在,然後編譯時會把註解信息放到了class文件,但JVM在加載類時,會忽略註解!JVM中(RUNTIME):註解在源代碼、字節碼文件中存在,並且在JVM加載類時,會把註解加載到JVM內存中(它是唯一可反射註解!

三:讀取註解,也就是使用反射註解,讀取註解裏面的屬性值!
使用反射註解,保留策略必須爲@Retention(RetentionPolicy.RUNTIME) 纔可以!!!
兩個方法:
getAnnotation(); 獲取作用目標上指定類型的註解!!
getAnnotations(); 獲取作用目標上所有的註解!!

public class Demo1 {

	public static void main(String[] args) throws Exception {
		//思路:得到作用目標,獲取指定類型的註解!
		
		//獲取註解上的值!
		Class<A> a = A.class;
		MyAnno1 anno1 = a.getAnnotation(MyAnno1.class);//註解也是一個類!
		System.out.println("name:"+anno1.name()+"\tage:"+anno1.age()+"\tsex:"+anno1.sex());
		
		//獲取方法上的註解的值
		Method method = a.getMethod("a"); //getMethod(name, parameterTypes); 第二個參數是可變參數直接可以不給!
		MyAnno1 annoOnMethod = method.getAnnotation(MyAnno1.class);
		System.out.println("name:"+annoOnMethod.name()+"\tage:"+annoOnMethod.age()+"\tsex:"+annoOnMethod.sex());
		
	}
}

@MyAnno1(name = "wzj",age = 22)
class A{
	
	@MyAnno1(name = "tom",age = 10)
	public void a() {
		
	}
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno1{
	String name();
	int age();
	char sex() default '男';
}

最後:加一個反射泛型的Demo

public class Demo1 {

	public static void main(String[] args) {
		//需求:在父類中得到子類傳過來的類型參數!!
		new C();
	}
}


class A<T>{

	public A() {
		//在這裏面得到子類的類型參數!,this爲什麼是子類對象,而不是父類對象!
//		Class clazz = this.getClass();
//		Type type = clazz.getGenericSuperclass(); //獲取傳遞給父類的參數化類型
//		ParameterizedType ptype = (ParameterizedType) type;
//		Type[] types = ptype.getActualTypeArguments();
//		Class c = (Class) types[0];
//		System.out.println(c.getSimpleName());
		
		Class c = (Class)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];//ParameterizedType:參數化類型
		System.out.println(c.getSimpleName());
	}
}


//<String>: 就是類型參數
class B extends A<String>{
	
	public B() {
		//那麼子類繼承了父類的構造方法嗎
		super();
	} 
}

class C extends A<Integer>{
	
}

來自一個雖然帥,但是菜的cxy

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章