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