更多內容請關注微信公衆號【Java技術江湖】html
這是一位阿里 Java 工程師的技術小站,做者黃小斜,專一 Java 相關技術:SSM、SpringBoot、MySQL、分佈式、中間件、集羣、Linux、網絡、多線程,偶爾講點Docker、ELK,同時也分享技術乾貨和學習經驗,致力於Java全棧開發!(關注公衆號後回覆」資料「便可領取 3T 免費技術學習資源以及我我原創的程序員校招指南、Java學習指南等資源)java
**
本節主要介紹Java反射的原理,使用方法以及相關的技術細節,而且介紹了關於Class類,註解等內容。git
具體代碼在個人GitHub中能夠找到程序員
https://github.com/h2pl/MyTech
文章首發於個人我的博客:github
https://h2pl.github.io/2018/0...
更多關於Java後端學習的內容請到個人CSDN博客上查看:數據庫
https://blog.csdn.net/a724888
反射(Reflection)是Java 程序開發語言的特徵之一,它容許運行中的 Java 程序獲取自身的信息,而且能夠操做類或對象的內部屬性。
Oracle官方對反射的解釋是編程
Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.後端
簡而言之,經過反射,咱們能夠在運行時得到程序或程序集中每個類型的成員和成員的信息。數組
程序中通常的對象的類型都是在編譯期就肯定下來的,而Java反射機制能夠動態地建立對象並調用其屬性,這樣的對象的類型在編譯期是未知的。因此咱們能夠經過反射機制直接建立對象,即便這個對象的類型在編譯期是未知的。安全
反射的核心是JVM在運行時才動態加載類或調用方法/訪問屬性,它不須要事先(寫代碼的時候或編譯期)知道運行對象是誰。
Java反射框架主要提供如下功能:
1.在運行時判斷任意一個對象所屬的類;2.在運行時構造任意一個類的對象;
3.在運行時判斷任意一個類所具備的成員變量和方法(經過反射甚至能夠調用private方法);
4.在運行時調用任意一個對象的方法
重點:是運行時而不是編譯時
不少人都認爲反射在實際的Java開發應用中並不普遍,其實否則。當咱們在使用IDE(如Eclipse,IDEA)時,當咱們輸入一個對象或類並想調用它的屬性或方法時,一按點號,編譯器就會自動列出它的屬性或方法,這裏就會用到反射。
反射最重要的用途就是開發各類通用框架。
不少框架(好比Spring)都是配置化的(好比經過XML文件配置JavaBean,Action之類的),爲了保證框架的通用性,它們可能須要根據配置文件加載不一樣的對象或類,調用不一樣的方法,這個時候就必須用到反射——運行時動態加載須要加載的對象。
舉一個例子,在運用Struts 2框架的開發中咱們通常會在struts.xml裏去配置Action,好比:
<action name="login" class="org.ScZyhSoft.test.action.SimpleLoginAction" method="execute"> <result>/shop/shop-index.jsp</result> <result name="error">login.jsp</result> </action>
配置文件與Action創建了一種映射關係,當View層發出請求時,請求會被StrutsPrepareAndExecuteFilter攔截,而後StrutsPrepareAndExecuteFilter會去動態地建立Action實例。
——好比咱們請求login.action,那麼StrutsPrepareAndExecuteFilter就會去解析struts.xml文件,檢索action中name爲login的Action,並根據class屬性建立SimpleLoginAction實例,並用invoke方法來調用execute方法,這個過程離不開反射。
對與框架開發人員來講,反射雖小但做用很是大,它是各類容器實現的核心。而對於通常的開發者來講,不深刻框架開發則用反射用的就會少一點,不過了解一下框架的底層機制有助於豐富本身的編程思想,也是頗有益的。
更多關於Class類和Object類的原理和介紹請見上一節
一、Class是一個類,一個描述類的類(也就是描述類自己),封裝了描述方法的Method,描述字段的Filed,描述構造器的Constructor等屬性
二、對象照鏡子後(反射)能夠獲得的信息:某個類的數據成員名、方法和構造器、某個類到底實現了哪些接口。
三、對於每一個類而言,JRE 都爲其保留一個不變的 Class 類型的對象。一個Class對象包含了特定某個類的有關信息。
四、Class 對象只能由系統創建對象
五、一個類在 JVM 中只會有一個Class實例
//總結一下就是,JDK有一個類叫作Class,這個類用來封裝全部Java類型,包括這些類的全部信息,JVM中類信息是放在方法區的。 //全部類在加載後,JVM會爲其在堆中建立一個Class<類名稱>的對象,而且每一個類只會有一個Class對象,這個類的全部對象都要經過Class<類名稱>來進行實例化。 //上面說的是JVM進行實例化的原理,固然實際上在Java寫代碼時只須要用 類名稱就能夠進行實例化了。 public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement { 虛擬機會保持惟一一 //經過類名.class得到惟一的Class對象。 Class<UserBean> cls = UserBean.class; //經過integer.TYPEl來獲取Class對象 Class<Integer> inti = Integer.TYPE; //接口本質也是一個類,同樣能夠經過.class獲取 Class<User> userClass = User.class;
上面咱們提到了反射能夠用於判斷任意對象所屬的類,得到Class對象,構造任意一個對象以及調用一個對象。這裏咱們介紹一下基本反射功能的實現(反射相關的類通常都在java.lang.relfect包裏)。
一、得到Class對象方法有三種
(1)使用Class類的forName靜態方法:
public static Class<?> forName(String className) ``` 在JDBC開發中經常使用此方法加載數據庫驅動: 要使用全類名來加載這個類,通常數據庫驅動的配置信息會寫在配置文件中。加載這個驅動前要先導入jar包 ```java Class.forName(driver);
(2)直接獲取某一個對象的class,好比:
//Class<?>是一個泛型表示,用於獲取一個類的類型。 Class<?> klass = int.class; Class<?> classInt = Integer.TYPE;
(3)調用某個對象的getClass()方法,好比:
StringBuilder str = new StringBuilder("123"); Class<?> klass = str.getClass();
通常地,咱們用instanceof關鍵字來判斷是否爲某個類的實例。同時咱們也能夠藉助反射中Class對象的isInstance()方法來判斷是否爲某個類的實例,它是一個Native方法:
==public native boolean isInstance(Object obj);==
經過反射來生成對象主要有兩種方式。
(1)使用Class對象的newInstance()方法來建立Class對象對應類的實例。
注意:利用newInstance建立對象:調用的類必須有無參的構造器
//Class<?>表明任何類的一個類對象。 //使用這個類對象能夠爲其餘類進行實例化 //由於jvm加載類之後自動在堆區生成一個對應的*.Class對象 //該對象用於讓JVM對進行全部*對象實例化。 Class<?> c = String.class; //Class<?> 中的 ? 是通配符,其實就是表示任意符合泛類定義條件的類,和直接使用 Class //效果基本一致,可是這樣寫更加規範,在某些類型轉換時能夠避免沒必要要的 unchecked 錯誤。 Object str = c.newInstance();
(2)先經過Class對象獲取指定的Constructor對象,再調用Constructor對象的newInstance()方法來建立實例。這種方法能夠用指定的構造器構造類的實例。
//獲取String所對應的Class對象 Class<?> c = String.class; //獲取String類帶一個String參數的構造器 Constructor constructor = c.getConstructor(String.class); //根據構造器建立實例 Object obj = constructor.newInstance("23333"); System.out.println(obj);
獲取某個Class對象的方法集合,主要有如下幾個方法:
getDeclaredMethods()方法返回類或接口聲明的全部方法,==包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法==。
public Method[] getDeclaredMethods() throws SecurityException
getMethods()方法返回某個類的全部公用(public)方法,==包括其繼承類的公用方法。==
public Method[] getMethods() throws SecurityException
getMethod方法返回一個特定的方法,其中第一個參數爲方法名稱,後面的參數爲方法的參數對應Class的對象
public Method getMethod(String name, Class<?>... parameterTypes)
只是這樣描述的話可能難以理解,咱們用例子來理解這三個方法:
本文中的例子用到了如下這些類,用於反射的測試。
//註解類,可可用於表示方法,能夠經過反射獲取註解的內容。 //Java註解的實現是不少注框架實現註解配置的基礎 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface Invoke { }
userbean的父類personbean
public class PersonBean { private String name; int id; public String getName() { return name; } public void setName(String name) { this.name = name; }
}
接口user
public interface User { public void login (); }
userBean實現user接口,繼承personbean
public class UserBean extends PersonBean implements User{ @Override public void login() { } class B { } public String userName; protected int i; static int j; private int l; private long userId; public UserBean(String userName, long userId) { this.userName = userName; this.userId = userId; } public String getName() { return userName; } public long getId() { return userId; } @Invoke public static void staticMethod(String devName,int a) { System.out.printf("Hi %s, I'm a static method", devName); } @Invoke public void publicMethod() { System.out.println("I'm a public method"); } @Invoke private void privateMethod() { System.out.println("I'm a private method"); } }
1 getMethods和getDeclaredMethods的區別
public class 動態加載類的反射 { public static void main(String[] args) { try { Class clazz = Class.forName("com.javase.反射.UserBean"); for (Field field : clazz.getDeclaredFields()) { // field.setAccessible(true); System.out.println(field); } //getDeclaredMethod*()獲取的是類自身聲明的全部方法,包含public、protected和private方法。 System.out.println("------共有方法------"); // getDeclaredMethod*()獲取的是類自身聲明的全部方法,包含public、protected和private方法。 // getMethod*()獲取的是類的全部共有方法,這就包括自身的全部public方法,和從基類繼承的、從接口實現的全部public方法。 for (Method method : clazz.getMethods()) { String name = method.getName(); System.out.println(name); //打印出了UserBean.java的全部方法以及父類的方法 } System.out.println("------獨佔方法------"); for (Method method : clazz.getDeclaredMethods()) { String name = method.getName(); System.out.println(name); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
2 打印一個類的全部方法及詳細信息:
public class 打印全部方法 { public static void main(String[] args) { Class userBeanClass = UserBean.class; Field[] fields = userBeanClass.getDeclaredFields(); //注意,打印方法時沒法獲得局部變量的名稱,由於jvm只知道它的類型 Method[] methods = userBeanClass.getDeclaredMethods(); for (Method method : methods) { //依次得到方法的修飾符,返回類型和名稱,外加方法中的參數 String methodString = Modifier.toString(method.getModifiers()) + " " ; // private static methodString += method.getReturnType().getSimpleName() + " "; // void methodString += method.getName() + "("; // staticMethod Class[] parameters = method.getParameterTypes(); Parameter[] p = method.getParameters(); for (Class parameter : parameters) { methodString += parameter.getSimpleName() + " " ; // String } methodString += ")"; System.out.println(methodString); } //注意方法只能獲取到其類型,拿不到變量名 /* public String getName() public long getId() public static void staticMethod(String int ) public void publicMethod() private void privateMethod()*/ } }
獲取類構造器的用法與上述獲取方法的用法相似。主要是經過Class類的getConstructor方法獲得Constructor類的一個實例,而Constructor類有一個newInstance方法能夠建立一個對象實例:
public class 打印構造方法 { public static void main(String[] args) { // constructors Class<?> clazz = UserBean.class; Class userBeanClass = UserBean.class; //得到全部的構造方法 Constructor[] constructors = userBeanClass.getDeclaredConstructors(); for (Constructor constructor : constructors) { String s = Modifier.toString(constructor.getModifiers()) + " "; s += constructor.getName() + "("; //構造方法的參數類型 Class[] parameters = constructor.getParameterTypes(); for (Class parameter : parameters) { s += parameter.getSimpleName() + ", "; } s += ")"; System.out.println(s); //打印結果//public com.javase.反射.UserBean(String, long, ) } } }
主要是這幾個方法,在此再也不贅述:
getFiled: 訪問公有的成員變量
getDeclaredField:全部已聲明的成員變量。但不能獲得其父類的成員變量
getFileds和getDeclaredFields用法同上(參照Method)
public class 打印成員變量 { public static void main(String[] args) { Class userBeanClass = UserBean.class; //得到該類的全部成員變量,包括static private Field[] fields = userBeanClass.getDeclaredFields(); for(Field field : fields) { //private屬性即便不用下面這個語句也能夠訪問 // field.setAccessible(true); //由於類的私有域在反射中默承認訪問,因此flag默認爲true。 String fieldString = ""; fieldString += Modifier.toString(field.getModifiers()) + " "; // `private` fieldString += field.getType().getSimpleName() + " "; // `String` fieldString += field.getName(); // `userName` fieldString += ";"; System.out.println(fieldString); //打印結果 // public String userName; // protected int i; // static int j; // private int l; // private long userId; } } }
當咱們從類中獲取了一個方法後,咱們就能夠用invoke()方法來調用這個方法。invoke方法的原型爲:
public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException public class 使用反射調用方法 { public static void main(String[] args) throws InvocationTargetException, IllegalAccessException, InstantiationException, NoSuchMethodException { Class userBeanClass = UserBean.class; //獲取該類全部的方法,包括靜態方法,實例方法。 //此處也包括了私有方法,只不過私有方法在用invoke訪問以前要設置訪問權限 //也就是使用setAccessible使方法可訪問,不然會拋出異常 // // IllegalAccessException的解釋是 // * An IllegalAccessException is thrown when an application tries // * to reflectively create an instance (other than an array), // * set or get a field, or invoke a method, but the currently // * executing method does not have access to the definition of // * the specified class, field, method or constructor. // getDeclaredMethod*()獲取的是類自身聲明的全部方法,包含public、protected和private方法。 // getMethod*()獲取的是類的全部共有方法,這就包括自身的全部public方法,和從基類繼承的、從接口實現的全部public方法。 //就是說,當這個類,域或者方法被設爲私有訪問,使用反射調用可是卻沒有權限時會拋出異常。 Method[] methods = userBeanClass.getDeclaredMethods(); // 獲取全部成員方法 for (Method method : methods) { //反射能夠獲取方法上的註解,經過註解來進行判斷 if (method.isAnnotationPresent(Invoke.class)) { // 判斷是否被 @Invoke 修飾 //判斷方法的修飾符是是static if (Modifier.isStatic(method.getModifiers())) { // 若是是 static 方法 //反射調用該方法 //類方法能夠直接調用,沒必要先實例化 method.invoke(null, "wingjay",2); // 直接調用,並傳入須要的參數 devName } else { //若是不是類方法,須要先得到一個實例再調用方法 //傳入構造方法須要的變量類型 Class[] params = {String.class, long.class}; //獲取該類指定類型的構造方法 //若是沒有這種類型的方法會報錯 Constructor constructor = userBeanClass.getDeclaredConstructor(params); // 獲取參數格式爲 String,long 的構造函數 //經過構造方法的實例來進行實例化 Object userBean = constructor.newInstance("wingjay", 11); // 利用構造函數進行實例化,獲得 Object if (Modifier.isPrivate(method.getModifiers())) { method.setAccessible(true); // 若是是 private 的方法,須要獲取其調用權限 // Set the {@code accessible} flag for this object to // * the indicated boolean value. A value of {@code true} indicates that // * the reflected object should suppress Java language access // * checking when it is used. A value of {@code false} indicates // * that the reflected object should enforce Java language access checks. //經過該方法能夠設置其可見或者不可見,不只能夠用於方法 //後面例子會介紹將其用於成員變量 //打印結果 // I'm a public method // Hi wingjay, I'm a static methodI'm a private method } method.invoke(userBean); // 調用 method,無須參數 } } } } }
數組在Java裏是比較特殊的一種類型,它能夠賦值給一個Object Reference。下面咱們看一看利用反射建立數組的例子:
public class 用反射建立數組 { public static void main(String[] args) { Class<?> cls = null; try { cls = Class.forName("java.lang.String"); } catch (ClassNotFoundException e) { e.printStackTrace(); } Object array = Array.newInstance(cls,25); //往數組裏添加內容 Array.set(array,0,"hello"); Array.set(array,1,"Java"); Array.set(array,2,"fuck"); Array.set(array,3,"Scala"); Array.set(array,4,"Clojure"); //獲取某一項的內容 System.out.println(Array.get(array,3)); //Scala } }
其中的Array類爲java.lang.reflect.Array類。咱們經過Array.newInstance()建立數組對象,它的原型是:
public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException { return newArray(componentType, length); }
而newArray()方法是一個Native方法,它在Hotspot JVM裏的具體實現咱們後邊再研究,這裏先把源碼貼出來
private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException;
阿丙的博客園
把每一件簡單的事情作好,就是不簡單;把每一件平凡的事情作好,就是不平凡!相信本身,創造奇蹟~~
博客園首頁聯繫管理
隨筆 - 441 文章 - 0 評論 - 53
註解Annotation實現原理與自定義註解例子
什麼是註解?
對於不少初次接觸的開發者來講應該都有這個疑問?Annontation是Java5開始引入的新特徵,中文名稱叫註解。它提供了一種安全的相似註釋的機制,用來將任何的信息或元數據(metadata)與程序元素(類、方法、成員變量等)進行關聯。爲程序的元素(類、方法、成員變量)加上更直觀更明瞭的說明,這些說明信息是與程序的業務邏輯無關,而且供指定的工具或框架使用。Annontation像一種修飾符同樣,應用於包、類型、構造方法、方法、成員變量、參數及本地變量的聲明語句中。
Java註解是附加在代碼中的一些元信息,用於一些工具在編譯、運行時進行解析和使用,起到說明、配置的功能。註解不會也不能影響代碼的實際邏輯,僅僅起到輔助性的做用。包含在 java.lang.annotation 包中。
註解的用處:
一、生成文檔。這是最多見的,也是java 最先提供的註解。經常使用的有@param @return 等 二、跟蹤代碼依賴性,實現替代配置文件功能。好比Dagger 2依賴注入,將來java開發,將大量註解配置,具備很大用處; 三、在編譯時進行格式檢查。如@override 放在方法前,若是你這個方法並非覆蓋了超類方法,則編譯時就能檢查出。
註解的原理:
註解本質是一個繼承了Annotation的特殊接口,其具體實現類是Java運行時生成的動態代理類。而咱們經過反射獲取註解時,返回的是Java運行時生成的動態代理對象$Proxy1。經過代理對象調用自定義註解(接口)的方法,會最終調用AnnotationInvocationHandler的invoke方法。該方法會從memberValues這個Map中索引出對應的值。而memberValues的來源是Java常量池。
元註解:
java.lang.annotation提供了四種元註解,專門註解其餘的註解(在自定義註解的時候,須要使用到元註解):
@Documented –註解是否將包含在JavaDoc中
@Retention –何時使用該註解
@Target –註解用於什麼地方
@Inherited – 是否容許子類繼承該註解
1.)@Retention– 定義該註解的生命週期
● RetentionPolicy.SOURCE : 在編譯階段丟棄。這些註解在編譯結束以後就再也不有任何意義,因此它們不會寫入字節碼。@Override, @SuppressWarnings都屬於這類註解。
● RetentionPolicy.CLASS : 在類加載的時候丟棄。在字節碼文件的處理中有用。註解默認使用這種方式
● RetentionPolicy.RUNTIME : 始終不會丟棄,運行期也保留該註解,所以可使用反射機制讀取該註解的信息。咱們自定義的註解一般使用這種方式。
2.)Target – 表示該註解用於什麼地方。默認值爲任何元素,表示該註解用於什麼地方。可用的ElementType參數包括
● ElementType.CONSTRUCTOR:用於描述構造器
● ElementType.FIELD:成員變量、對象、屬性(包括enum實例)
● ElementType.LOCAL_VARIABLE:用於描述局部變量
● ElementType.METHOD:用於描述方法
● ElementType.PACKAGE:用於描述包
● ElementType.PARAMETER:用於描述參數
● ElementType.TYPE:用於描述類、接口(包括註解類型) 或enum聲明
3.)@Documented–一個簡單的Annotations標記註解,表示是否將註解信息添加在java文檔中。
4.)@Inherited – 定義該註釋和子類的關係
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的類型是被繼承的。若是一個使用了@Inherited修飾的annotation類型被用於一個class,則這個annotation將被用於該class的子類。
常見標準的Annotation:
1.)Override
java.lang.Override是一個標記類型註解,它被用做標註方法。它說明了被標註的方法重載了父類的方法,起到了斷言的做用。若是咱們使用了這種註解在一個沒有覆蓋父類方法的方法時,java編譯器將以一個編譯錯誤來警示。
2.)Deprecated
Deprecated也是一種標記類型註解。當一個類型或者類型成員使用@Deprecated修飾的話,編譯器將不鼓勵使用這個被標註的程序元素。因此使用這種修飾具備必定的「延續性」:若是咱們在代碼中經過繼承或者覆蓋的方式使用了這個過期的類型或者成員,雖然繼承或者覆蓋後的類型或者成員並非被聲明爲@Deprecated,但編譯器仍然要報警。
3.)SuppressWarnings
SuppressWarning不是一個標記類型註解。它有一個類型爲String[]的成員,這個成員的值爲被禁止的警告名。對於javac編譯器來說,被-Xlint選項有效的警告名也一樣對@SuppressWarings有效,同時編譯器忽略掉沒法識別的警告名。
@SuppressWarnings("unchecked")
自定義註解:
自定義註解類編寫的一些規則:
PS:自定義註解須要使用到元註解
自定義註解實例:
FruitName.java
按 Ctrl+C 複製代碼
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
按 Ctrl+C 複製代碼
FruitColor.java
按 Ctrl+C 複製代碼
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitColor {
/** * 顏色枚舉 */ public enum Color{ BLUE,RED,GREEN}; /** * 顏色屬性 */ Color fruitColor() default Color.GREEN;
}
按 Ctrl+C 複製代碼
FruitProvider.java
按 Ctrl+C 複製代碼
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitProvider {
/** * 供應商編號 */ public int id() default -1; /** * 供應商名稱 */ public String name() default ""; /** * 供應商地址 */ public String address() default "";
}
按 Ctrl+C 複製代碼
FruitInfoUtil.java
按 Ctrl+C 複製代碼
import java.lang.reflect.Field;
/**
*/
public class FruitInfoUtil {
public static void getFruitInfo(Class<?> clazz){ String strFruitName=" 水果名稱:"; String strFruitColor=" 水果顏色:"; String strFruitProvicer="供應商信息:"; Field[] fields = clazz.getDeclaredFields(); for(Field field :fields){ if(field.isAnnotationPresent(FruitName.class)){ FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class); strFruitName=strFruitName+fruitName.value(); System.out.println(strFruitName); } else if(field.isAnnotationPresent(FruitColor.class)){ FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class); strFruitColor=strFruitColor+fruitColor.fruitColor().toString(); System.out.println(strFruitColor); } else if(field.isAnnotationPresent(FruitProvider.class)){ FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class); strFruitProvicer=" 供應商編號:"+fruitProvider.id()+" 供應商名稱:"+fruitProvider.name()+" 供應商地址:"+fruitProvider.address(); System.out.println(strFruitProvicer); } } }
}
按 Ctrl+C 複製代碼
Apple.java
按 Ctrl+C 複製代碼
import test.FruitColor.Color;
/**
*/
public class Apple {
@FruitName("Apple") private String appleName; @FruitColor(fruitColor=Color.RED) private String appleColor; @FruitProvider(id=1,name="陝西紅富士集團",address="陝西省西安市延安路89號紅富士大廈") private String appleProvider; public void setAppleColor(String appleColor) { this.appleColor = appleColor; } public String getAppleColor() { return appleColor; } public void setAppleName(String appleName) { this.appleName = appleName; } public String getAppleName() { return appleName; } public void setAppleProvider(String appleProvider) { this.appleProvider = appleProvider; } public String getAppleProvider() { return appleProvider; } public void displayName(){ System.out.println("水果的名字是:蘋果"); }
}
按 Ctrl+C 複製代碼
FruitRun.java
按 Ctrl+C 複製代碼
/**
*/
public class FruitRun {
public static void main(String[] args) { FruitInfoUtil.getFruitInfo(Apple.class); }
}
按 Ctrl+C 複製代碼
運行結果是:
水果名稱:Apple
水果顏色:RED
供應商編號:1 供應商名稱:陝西紅富士集團 供應商地址:陝西省西安市延安路89號紅富士大廈
參考連接:
[1]http://www.cnblogs.com/peida/...
[2]http://www.cnblogs.com/whoisl...
[3]http://blog.csdn.net/lylwo317...