前言
注解就是源代碼的元數(shù)據(jù)谎势,通熟的講就是代碼中的標(biāo)簽凛膏。注解就有如下的特點(diǎn):
- 注解是一個(gè)附屬品,依賴于其他元素(包脏榆、類猖毫、方法、屬性等等)存在须喂。
- 注解本身沒有作用吁断,在恰當(dāng)?shù)臅r(shí)候由外部程序進(jìn)行解析才會(huì)發(fā)生作用。
注解有哪些坞生?
- 按來源分
- JDK 自帶注解仔役,例如:@Override, @Deprecated, @SuppressWornings 。
- 第三方注解是己。
- 自定義注解又兵。
- 按生命周期劃分
- SOURCE:只存在于源代碼中,編譯成 class 文件就不存在了卒废。
- Class:存在于源代碼中和 class 文件中沛厨。
- RUNTIME:注解保留到運(yùn)行時(shí)乘盼。
什么是元注解?
元注解指的是用于構(gòu)成注解的注解俄烁,包括如下幾個(gè):
- @Retention:指明 Annotation 的生命周期绸栅,傳入的值是一個(gè)枚舉類型,可選值為:
RetentionPolicy.SOURCE
RetentionPolicy.CLASS
RetentionPolicy.RUNTIME
- @Target:指明 Annotation 可以修飾程序哪些元素页屠,傳入的值為ElemetType[] 類型粹胯,值可為:
-
ElementType.CONSTRUCTOR
:構(gòu)造器 -
ElementType.FIELD
:屬性 -
ElementType.LOCAL_VARIABLE
:局部變量 -
ElementType.METHOD
:方法 -
ElementType.PACKAGE
:包 -
ElementType.PARAMETER
:參數(shù) -
ElementType.TYPE
:類、接口(包括注解類型和 enum 聲明)
-
- @Documented:使用此修飾的注解將會(huì)被 javadoc 工具提取成文檔辰企,使用此注解风纠,其 @Retention 必須被設(shè)置為
RetentionPolicy.RUNTIME
。 - @Inherited:具有繼承性牢贸。
如何自定義注解竹观?
自定義注解需要注意的問題:
使用 @interface 關(guān)鍵字定義。
自動(dòng)繼承
java.lang.annotation.Annotation
接口潜索。配置參數(shù)的類型只能是八大基本類型臭增、String、Class竹习、enum誊抛、Annotation 和對應(yīng)的數(shù)組類型。
-
配置參數(shù)聲明的語法格式如下([] 表示可省略):
類型 變量名() [default 默認(rèn)值];
如果只有一個(gè)配置參數(shù)整陌,其參數(shù)名必須為 value拗窃。
如果定義的注解含有配置參數(shù),那在使用注解時(shí)泌辫,必須指定參數(shù)值随夸,指定形式為:“參數(shù)名=參數(shù)值”。如果只有一個(gè)參數(shù)震放,直接寫參數(shù)值即可宾毒,定義中指定了默認(rèn)值的參數(shù)可以不指定值,但沒有的一定要指定值澜搅。
沒有成員的注解為標(biāo)記伍俘,包含成員的稱為元數(shù)據(jù)。
自定義注解實(shí)例(定義和使用)
參考代碼:
(1)Test01.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class Test01 {
@Info(name = "張三",address="北京")
public void test01(){
}
@One("value")
public void test02(){
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
@interface Info {
String name();
String address();
int age()default 18;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@interface One{
String value();
}
}
反射
什么是反射勉躺?
反射指的是程序在運(yùn)行期間借助反射 API 取得任何類的內(nèi)部信息癌瘾,并通過這些內(nèi)部信息去操作對應(yīng)對象的內(nèi)部屬性和方法。
任何一個(gè)類饵溅,在第一次使用時(shí)妨退,就會(huì)被 JVM 加載到堆內(nèi)存的方法區(qū)中。JVM 加載類成功后,就會(huì)在方法區(qū)中產(chǎn)生一個(gè)對應(yīng)的 Class 對象(一個(gè)類只要一個(gè) Class 對象)咬荷,這個(gè) Class 對象包含被加載類的全部結(jié)構(gòu)信息冠句。
如何獲取class對象?
(1)類的 class 屬性
每一個(gè)類幸乒,都有一個(gè) class 靜態(tài)屬性懦底,這個(gè)靜態(tài)屬性就是類對應(yīng)的 Class 對象。
1 Class<Person> cl1 = Person.class;
(2)Object 對象 的 getClass() 方法
1 Person p1 = new Person()罕扎;
2 Class<Person> cl2 = (Class<Person>) p1.getClass();
(3)通過 Class 類的 forName() 方法(最常用)
1 try {
2 Class cl3 = Class.forName("com.llm.hkl.Person");
3 } catch (ClassNotFoundException e) {
4 e.printStackTrace();
5 }
(4)通過 ClassLoader 類(不常用)
1 ClassLoader cl = Person.class.getClassLoader();
2 try {
3 Class cl4 = cl.loadClass("com.llm.hkl.Person");
4 } catch (ClassNotFoundException e) {
5 e.printStackTrace();
6 }
如何使用反射聚唐?
反射的基本使用包括創(chuàng)建對象,設(shè)置屬性和調(diào)用方法腔召。Class 對象中大多數(shù) get 方法有 Declared 和無 Declared杆查,他們的區(qū)別是:
- 無 Declared:只能獲取到 public 修飾的,包括當(dāng)前類和所有父類臀蛛。
- 有 Declared:獲取到當(dāng)前類所有的(含有 private)亲桦,但不包括其父類。
反射實(shí)例:
Person類和注解類(準(zhǔn)備):
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Info(name = "張三", habbit = "編程")
public class Person {
@Filed("張三")
private String name;
public String habbit;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHabbit() {
return habbit;
}
public void setHabbit(String habbit) {
this.habbit = habbit;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", habbit='" + habbit + '\'' +
", age=" + age +
'}';
}
private String say(String str) {
String str1 = name + "說:" + str;
System.out.println(str1);
return str1;
}
public void eat(String food) {
System.out.println(name + "吃" + food);
}
public Person() {
}
public Person(String name, String habbit, int age) {
this.name = name;
this.habbit = habbit;
this.age = age;
}
private Person(String name, String habbit) {
this.name = name;
this.habbit = habbit;
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@interface Info {
String name();
String habbit();
int age() default 18;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Filed{
String value();
}
}
reflect用法一(獲取類的基本信息):
獲得類的名字
獲得類的屬性
獲得指定屬性的值
獲得類的方法
獲得指定方法
獲取構(gòu)造器
獲得指定的構(gòu)造器
Class<?> person = Class.forName("Person");
//獲得類的名字
System.out.println("<-----------------------------------獲得類的名字-------------------------->");
String name = person.getName();
System.out.println(name);
//獲得類的屬性
System.out.println("<-------------------------------------獲得類的屬性--------------------->");
//僅public
System.out.println("<-----------------getFields----------------->");
Field[] fields = person.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("<-----------------getDeclaredFields----------------->");
Field[] declaredFields = person.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//獲得指定屬性的值
System.out.println("<--------------------獲得類的指定屬性--------------------------------------->");
Field name1 = person.getDeclaredField("name");
System.out.println(name1);
//獲得類的方法
System.out.println("<--------------------獲得類的方法--------------------------------------->");
//僅public
System.out.println("<-----------------getMethods----------------->");
Method[] methods = person.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("<-----------------getDeclaredMethods----------------->");
Method[] declaredMethods = person.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
//獲得指定方法
System.out.println("<-------------------------獲得類的指定方法--------------------------------------->");
Method say = person.getDeclaredMethod("say",String.class);
System.out.println(say);
//獲取構(gòu)造器
System.out.println("<--------------------------獲得類的構(gòu)造器--------------------------------->");
System.out.println("<-----------------getConstructors----------------->");
//僅public
Constructor<?>[] constructors = person.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor);
}
System.out.println("<-----------------getDeclaredConstructors----------------->");
Constructor<?>[] declaredConstructors = person.getDeclaredConstructors();
for (Constructor<?> declaredConstructor : declaredConstructors) {
System.out.println(declaredConstructor);
}
//獲得指定的構(gòu)造器
System.out.println("<---------------------------獲得類指定的構(gòu)造器------------------------------>");
Constructor<?> declaredConstructor = person.getDeclaredConstructor(String.class, String.class, int.class);
System.out.println(declaredConstructor);
reflect用法二(創(chuàng)建并操作對象):
反射方式創(chuàng)建對象
調(diào)用無參構(gòu)造器創(chuàng)建對象
通過有參構(gòu)造器
通過私有的構(gòu)造器
通過反射設(shè)置公有屬性
通過反射設(shè)置私有屬性
通過反射調(diào)用方法
通過反射調(diào)用私有方法
Class<?> person = Class.forName("Person");
// 反射方式創(chuàng)建對象
System.out.println("<-----反射方式創(chuàng)建對象----->");
Person instance01 = (Person) person.newInstance();
System.out.println(instance01);
// 調(diào)用無參構(gòu)造器創(chuàng)建對象
System.out.println("<-----調(diào)用無參構(gòu)造器創(chuàng)建對象----->");
Constructor<?> noneConstructor = person.getDeclaredConstructor();
Person instance02 = (Person) noneConstructor.newInstance();
System.out.println(instance02);
// 調(diào)用有參構(gòu)造器創(chuàng)建對象
System.out.println("<-----調(diào)用有參構(gòu)造器創(chuàng)建對象----->");
Constructor<?> constructor = person.getDeclaredConstructor(String.class, String.class, int.class);
Person instance03 = (Person) constructor.newInstance("張三", "編程", 18);
System.out.println(instance03);
// 調(diào)用私有的構(gòu)造器創(chuàng)建對象
System.out.println("<-----調(diào)用私有的構(gòu)造器創(chuàng)建對象----->");
java.lang.reflect.Constructor<?> privateConstructor = person.getDeclaredConstructor(String.class, String.class);
privateConstructor.setAccessible(true);
Object instance04 = privateConstructor.newInstance("張三", "編程");
System.out.println(instance04);
// 通過反射設(shè)置公有屬性
System.out.println("<-----通過反射設(shè)置公有屬性----->");
Field habbit = person.getDeclaredField("habbit");
habbit.set(instance01, "編程");
System.out.println(instance01);
// 通過反射設(shè)置私有屬性
System.out.println("<-----通過反射設(shè)置私有屬性----->");
Field name = person.getDeclaredField("name");
name.setAccessible(true);
name.set(instance01, "張三");
System.out.println(instance01);
// 通過反射調(diào)用公有方法
System.out.println("<-----通過反射調(diào)公用方法----->");
Method eat = person.getDeclaredMethod("eat", String.class);
eat.invoke(instance01,"飯");
// 通過反射調(diào)用私有方法
System.out.println("<-----通過反射調(diào)用私有方法----->");
Method say = person.getDeclaredMethod("say", String.class);
say.setAccessible(true);
say.invoke(instance01,"呵呵");
reflect用法三(獲取泛型信息):
Java采用泛型擦除的機(jī)制來引入泛型,Java中的泛型僅僅是給編譯器 Javac使用的,確保數(shù)據(jù)的安全性和免去強(qiáng)制類型轉(zhuǎn)換問題,但是,一旦編譯完成,所有和泛型有關(guān)的類型全部擦除浊仆。
為了通過反射操作這些類型,Java新增了 ParameterizedType, GenericArrayTypeType Variable和 WildcardType幾種類型來代表不能被歸一到class類中的類型但是又和原始類型齊名的類型客峭。
ParameterizedType:表示一種參數(shù)化類型比如 Collection< String>
GenericArrayType:表示種元素類型是參數(shù)化類型或者類型變量的數(shù)組類型
TypeVariable:是各種類型變量的公共父接口
WildcardType:代表種通配符類型表達(dá)式
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class Test03 {
public void test01(Map<String, Person> map, List<Person> list) {
System.out.println("test01");
}
public Map<String, Person> test02(){
System.out.println("test02");
return null;
}
public static void main(String[] args) throws Exception {
Class<Test03> test03 = Test03.class;
System.out.println("<--------test01---------->");
Method test01 = test03.getDeclaredMethod("test01", Map.class, List.class);
Type[] genericParameterTypes = test01.getGenericParameterTypes();
for (Type genericParameterType : genericParameterTypes) {
System.out.println(genericParameterType);
if (genericParameterType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
System.out.println("<--------test02---------->");
Method test02 = test03.getDeclaredMethod("test02");
Type genericReturnType = test02.getGenericReturnType();
System.out.println(genericReturnType);
if (genericReturnType instanceof ParameterizedType) {
Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}
}
}
運(yùn)行結(jié)果:
reflect用法四(獲取注解信息):
獲取類上的注解
獲取屬性上的注解
獲取方法上的注解
Class<?> person = Class.forName("Person");
System.out.println("<----------獲取類上的注解------------->");
//獲取類上的注解
Info annotation = person.getAnnotation(Info.class);
System.out.println(annotation.name());
System.out.println(annotation.habbit());
System.out.println(annotation.age());
System.out.println("<----------獲取屬性上的注解------------->");
//獲取屬性上的注解
Field name = person.getDeclaredField("name");
Person.Filed file = name.getAnnotation(Person.Filed.class);
String value = file.value();
System.out.println(value);
//獲取方法上的注解 略。氧卧。桃笙。
運(yùn)行結(jié)果:
最后
感謝你看到這里,看完有什么的不懂的可以在評論區(qū)問我沙绝,覺得文章對你有幫助的話記得給我點(diǎn)個(gè)贊,每天都會(huì)分享java相關(guān)技術(shù)文章或行業(yè)資訊鼠锈,歡迎大家關(guān)注和轉(zhuǎn)發(fā)文章闪檬!