企業(yè)網(wǎng)盤怎么下載文件seo是什么服
Java注解以及自定義注解
要深入學(xué)習(xí)注解,我們就必須能定義自己的注解,并使用注解,在定義自己的注解之前,我們就必須要了解Java為
我們提供的元注解和相關(guān)定義注解的語法。
1、注解
1.1 注解的官方定義
注解是一種元數(shù)據(jù)形式。即注解是屬于java的一種數(shù)據(jù)類型,和類、接口、數(shù)組、枚舉類似。
注解用來修飾,類、方法、變量、參數(shù)、包。
注解不會對所修飾的代碼產(chǎn)生直接的影響。
1.2 注解的使用范圍
注解有許多用法,其中有:為編譯器提供信息 - 注解能被編譯器檢測到錯誤或抑制警告。編譯時和部署時的處理 -
軟件工具能處理注解信息從而生成代碼,XML文件等等。運行時的處理 - 有些注解在運行時能被檢測到。
2、元注解
一個最最基本的注解定義就只包括了兩部分內(nèi)容:1、注解的名字;2、注解包含的類型元素。但是,我們在使用
JDK自帶注解的時候發(fā)現(xiàn),有些注解只能寫在方法上面(比如@Override);有些卻可以寫在類的上面(比如
@Deprecated)。當(dāng)然除此以外還有很多細節(jié)性的定義,那么這些定義該如何做呢?接下來就該元注解出場了!
元注解:專門修飾注解的注解。它們都是為了更好的設(shè)計自定義注解的細節(jié)而專門設(shè)計的。Java5.0定義了4個標準
的meta-annotation類型,它們被用來提供對其它 annotation類型作說明。
Java5.0 定義的元注解:
1、@Target
2、@Retention
3、@Documented
4、@Inherited
這些類型和它們所支持的類在java.lang.annotation
包中可以找到。下面我們看一下每個元注解的作用和相應(yīng)
分參數(shù)的使用說明。
2.1 @Target
@Target注解,是專門用來限定某個自定義注解能夠被應(yīng)用在哪些Java元素上面的。
@Target說明了Annotation所修飾的對象范圍:Annotation可被用于 packages、types(類、接口、枚舉、
Annotation類型)、類型成員(方法、構(gòu)造方法、成員變量、枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量、
catch參數(shù))。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標。
作用:用于描述注解的使用范圍(即被描述的注解可以用在什么地方)
取值(ElementType)有:
1、CONSTRUCTOR
:用于描述構(gòu)造器
2、FIELD
:用于描述域
3、LOCAL_VARIABLE
:用于描述局部變量
4、METHOD
:用于描述方法
5、PACKAGE
:用于描述包
6、PARAMETER
:用于描述參數(shù)
7、TYPE
:用于描述類、接口(包括注解類型) 或enum聲明
它使用一個枚舉類型定義如下:
public enum ElementType {/** 類,接口(包括注解類型)或枚舉的聲明 */TYPE,/** 屬性的聲明 */FIELD,/** 方法的聲明 */METHOD,/** 方法形式參數(shù)聲明 */PARAMETER,/** 構(gòu)造方法的聲明 */CONSTRUCTOR,/** 局部變量聲明 */LOCAL_VARIABLE,/** 注解類型聲明 */ANNOTATION_TYPE,/** 包的聲明 */PACKAGE,TYPE_PARAMETER,TYPE_USE
}
使用實例:
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
public @interface Table {/*** 數(shù)據(jù)表名稱注解,默認值為類名稱* @return*/public String tableName() default "className";
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;//@CherryAnnotation被限定只能使用在類、接口或方法上面
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface CherryAnnotation {String name();int age() default 18;int[] array();
}
注解Table
可以用于注解類、接口(包括注解類型) 或enum聲明,而注解NoDBColumn
僅可用于注解類的成員變
量。
2.2 @Retention
@Retention注解,翻譯為持久力、保持力。即用來修飾自定義注解的生命力。
注解的生命周期有三個階段:1、Java源文件階段;2、編譯到class文件階段;3、運行期階段。同樣使用了
RetentionPolicy 枚舉類型定義了三個階段:
作用:表示需要在什么級別保存該注釋信息,用于描述注解的生命周期(即被描述的注解在什么范圍內(nèi)有效)
取值(RetentionPoicy)有:
1、SOURCE
:在源文件中有效(即源文件保留)
2、CLASS
:在class文件中有效(即class保留)
3、RUNTIME
:在運行時有效(即運行時保留)
Retention meta-annotation類型有唯一的value作為成員,它的取值來自
java.lang.annotation.RetentionPolicy
的枚舉類型值。
public enum RetentionPolicy {// 注解將被編譯器忽略掉SOURCE,// 注解將被編譯器記錄在class文件中,但在運行時不會被虛擬機保留,這是一個默認的行為CLASS,// 注解將被編譯器記錄在class文件中,而且在運行時會被虛擬機保留,因此它們能通過反射被讀取到RUNTIME
}
我們再詳解一下:
如果一個注解被定義為RetentionPolicy.SOURCE
,則它將被限定在Java源文件中,那么這個注解即不會參與編
譯也不會在運行期起任何作用,這個注解就和一個注釋是一樣的效果,只能被閱讀Java文件的人看到;
如果一個注解被定義為RetentionPolicy.CLASS
,則它將被編譯到Class文件中,那么編譯器可以在編譯時根據(jù)
注解做一些處理動作,但是運行時JVM(Java虛擬機)會忽略它,我們在運行期也不能讀取到;
如果一個注解被定義為RetentionPolicy.RUNTIME
,那么這個注解可以在運行期的加載階段被加載到Class對象
中。那么在程序運行階段,我們可以通過反射得到這個注解,并通過判斷是否有這個注解或這個注解中屬性的值,
從而執(zhí)行不同的程序代碼段。我們實際開發(fā)中的自定義注解幾乎都是使用的RetentionPolicy.RUNTIME
;在默認
的情況下,自定義注解是使用的RetentionPolicy.CLASS
。
具體實例如下:
package com.test3;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 Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}
Column注解的的RetentionPolicy的屬性值是RUNTIME,這樣注解處理器可以通過反射,獲取到該注解的屬性
值,從而去做一些運行時的邏輯處理。
2.3 @Documented
@Documented注解,是被用來指定自定義注解是否能隨著被定義的java文件生成到JavaDoc文檔當(dāng)中,因此可以
被例如javadoc此類的工具文檔化。
Documented是一個標記注解,沒有成員。
package com.test3;import java.lang.annotation.*;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column1 {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}
2.4 @Inherited
@Inherited注解,是指定某個自定義注解如果寫在了父類的聲明部分,那么子類的聲明部分也能自動擁有該注
解。@Inherited注解只對那些@Target被定義為ElementType.TYPE
的自定義注解起作用。
@Inherited 元注解是一個標記注解,@Inherited闡述了某個被標注的類型是被繼承的。如果一個使用了
@Inherited修飾的annotation類型被用于一個class,則這個annotation將被用于該class的子類。
注意:@Inherited annotation類型是被標注過的class的子類所繼承。類并不從它所實現(xiàn)的接口繼承annotation,
方法并不從它所重載的方法繼承annotation。
當(dāng)@Inherited annotation類型標注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強了這
種繼承性。如果我們使用java.lang.reflect去查詢一個@Inherited annotation類型的annotation時,反射代碼檢查
將展開工作:檢查class和其父類,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn),或者到達類繼承結(jié)構(gòu)的頂層。
實例代碼:
package com.test3;import java.lang.annotation.Inherited;@Inherited
public @interface Greeting {public enum FontColor {BULE, RED, GREEN};String name();FontColor fontColor() default FontColor.GREEN;
}
注解的繼承依賴如下一個因素:
1、首先要想Annotation
能被繼承,需要在注解定義的時候加上@Inherited
,并且如果要被反射應(yīng)用的話,還
需要@Retention(RetentionPolicy.RUNTIME)
標識。
2、JDK文檔中說明的是:只有在類上應(yīng)用Annotation
才能被繼承,而實際應(yīng)用結(jié)果是:除了類上應(yīng)用的
Annotation
能被繼承外,沒有被重寫的方法的Annotation
也能被繼承。
3、當(dāng)方法被重寫后,Annotation
不會被繼承。
4、Annotation
的繼承不能應(yīng)用在接口上。
3、自定義注解
使用@interface自定義注解時,自動繼承了java.lang.annotation.Annotation接口,由編譯程序自動完成其他細
節(jié)。在定義注解時,不能繼承其他的注解或接口。@interface用來聲明一個注解,其中的每一個方法實際上是聲
明了一個配置參數(shù)。方法的名稱就是參數(shù)的名稱,返回值類型就是參數(shù)的類型(返回值類型只能是基本類型、
Class、String、enum)??梢酝ㄟ^default來聲明參數(shù)的默認值。
3.1 定義注解格式
public @interface 注解名 {定義體}
public @interface CherryAnnotation {
}
根據(jù)我們在自定義類的經(jīng)驗,在類的實現(xiàn)部分無非就是書寫構(gòu)造、屬性或方法。但是,在自定義注解中,其實現(xiàn)
只能定義一個東西:注解類型元素(annotation type element)。語法:
public @interface CherryAnnotation {public String name();public int age();public int[] array();
}
public @interface CherryAnnotation {public String name();public int age() default 18;public int[] array();
}
3.2 注解參數(shù)的可支持數(shù)據(jù)類型
1、所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short
)
2、String
類型
3、Class
類型
4、enum
類型
5、Annotation
類型
6、以上所有類型的數(shù)組
注解里面定義的是:注解類型元素!
3.3 定義注解類型元素時需要注意如下幾點
1、只能用public或默認(default)這兩個訪問權(quán)修飾,例如String value();
這里把方法設(shè)為default默認類型。
2、參數(shù)成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據(jù)類型和 String,
Enum,Class,annotations等數(shù)據(jù)類型,以及這一些類型的數(shù)組。
3、如果只有一個參數(shù)成員,最好把參數(shù)名稱設(shè)為value
,后加小括號。
4、()
不是定義方法參數(shù)的地方,也不能在括號中定義任何參數(shù),僅僅只是一個特殊的語法。
5、default
代表默認值,值必須和第2點定義的類型一致。
6、如果沒有默認值,代表后續(xù)使用注解時必須給該類型元素賦值。
可以看出,注解類型元素的語法非常奇怪,即又有屬性的特征(可以賦值),又有方法的特征(打上了一對括
號)。但是這么設(shè)計是有道理的,我們在后面的章節(jié)中可以看到:注解在定義好了以后,使用的時候操作元素類型
像在操作屬性,解析的時候操作元素類型像在操作方法。
3.4 簡單的自定義注解和使用注解實例
package com.test;import java.lang.annotation.*;/*** 水果名稱注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test;import java.lang.annotation.*;/*** 水果顏色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 顏色枚舉*/public enum Color {BULE, RED, GREEN};/*** 顏色屬性** @return*/Color fruitColor() default Color.GREEN;}
package com.test;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = FruitColor.Color.RED)private String appleColor;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;}
}
3.5 注解元素的默認值
注解元素必須有確定的值,要么在定義注解的默認值中指定,要么在使用注解時指定,非基本類型的注解元素的值
不可為null。因此,使用空字符串或0作為默認值是一種常用的做法。這個約束使得處理器很難表現(xiàn)一個元素的存
在或缺失的狀態(tài),因為每個注解的聲明中,所有元素都存在,并且都具有相應(yīng)的值,為了繞開這個約束,我們只能
定義一些特殊的值,例如空字符串或者負數(shù),一次表示某個元素不存在,在定義注解時,這已經(jīng)成為一個習(xí)慣用
法。
package com.test;import java.lang.annotation.*;/*** 水果供應(yīng)者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供應(yīng)商編號** @return*/public int id() default -1;/*** 供應(yīng)商名稱** @return*/public String name() default "";/*** 供應(yīng)商地址** @return*/public String address() default "";
}
3.6 特殊語法
特殊語法一
如果注解本身沒有注解類型元素,那么在使用注解的時候可以省略()
,直接寫為:@注解名
,它和標準語法
@注解名()
等效!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}
//等效于 @FirstAnnotation()
@FirstAnnotation
public class JavaBean{
}
特殊語法二
如果注解本身只有一個注解類型元素,而且命名為value,那么在使用注解的時候可以直接使用:
@注解名(注解值)
,其等效于:@注解名(value = 注解值)
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {String value();
}
//等效于 @SecondAnnotation(value = "this is second annotation")
@SecondAnnotation("this is annotation")
public class JavaBean{
}
特殊用法三
如果注解中的某個注解類型元素是一個數(shù)組類型,在使用時又出現(xiàn)只需要填入一個值的情況,那么在使用注解時可
直接寫為:@注解名(類型名 = 類型值)
,它和標準寫法:@注解名(類型名 = {類型值})
等效!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {String[] name();
}
//等效于 @ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
}
特殊用法四
如果一個注解的@Target是定義為Element.PACKAGE,那么這個注解是配置在package-info.java
中的,而不能
直接在某個類的package代碼上面配置。
上面三節(jié)定義了注解,并在需要的時候給相關(guān)類,類屬性加上注解信息,如果沒有響應(yīng)的注解信息處理流程,注解
可以說是沒有實用價值。如何讓注解真真的發(fā)揮作用,主要就在于注解處理方法,下一步我們將學(xué)習(xí)注解信息的獲
取和處理!
4、自定義注解的配置使用
基于上一節(jié),已對注解有了一個基本的認識:注解其實就是一種標記,可以在程序代碼中的關(guān)鍵節(jié)點(類、方法、
變量、參數(shù)、包)上打上這些標記,然后程序在編譯時或運行時可以檢測到這些標記從而執(zhí)行一些特殊操作。因此
可以得出自定義注解使用的基本流程:
第一步,定義注解——相當(dāng)于定義標記;
第二步,配置注解——把標記打在需要用到的程序代碼中;
第三步,解析注解——在編譯期或運行時檢測到標記,并進行特殊操作。
4.1 在具體的Java類上使用注解
首先,定義一個注解和一個供注解修飾的簡單Java類。
package com.test1;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {String name();// 類型元素int age() default 18;int[] score();
}
package com.test1;public class Student {public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}
簡單分析下:
CherryAnnotation的@Target定義為ElementType.METHOD,那么它書寫的位置應(yīng)該在方法定義的上方,即:
public void study(int times)之上。由于我們在CherryAnnotation中定義的有注解類型元素,而且有些元素是沒有
默認值的,這要求我們在使用的時候必須在標記名后面打上(),并且在()內(nèi)以“元素名=元素值“的形式挨個填上所有
沒有默認值的注解類型元素(有默認值的也可以填上重新賦值),中間用“,”號分割。
所以最終書寫形式如下:
package com.test1;public class Student {@CherryAnnotation(name = "cherry-peng", age = 23, score = {99, 66, 77})public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}
4.2 自定義注解的運行時解析(反射操作獲取注解)
這一節(jié)是使用注解的核心,讀完此節(jié)即可明白,如何在程序運行時檢測到注解,并進行一系列特殊操作!
只有當(dāng)注解的保持力處于運行階段,即使用@Retention(RetentionPolicy.RUNTIME)
修飾注解時,才能在JVM
運行時,檢測到注解,并進行一系列特殊操作。
在運行期探究和使用編譯期的內(nèi)容(編譯期配置的注解),要用到Java中的靈魂技術(shù)——反射!
Java SE5擴展了反射機制的API,以幫助程序員快速的構(gòu)造自定義注解處理器。
package com.test1;import java.lang.reflect.Method;/*** @author zhangshixing* @date 2021年11月01日 9:32*/
public class TestAnnotation {public static void main(String[] args){try {//獲取Student的Class對象Class stuClass = Class.forName("com.test1.Student");//說明一下,這里形參不能寫成Integer.class,應(yīng)寫為int.classMethod stuMethod = stuClass.getMethod("study",int.class);if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){System.out.println("Student類上配置了CherryAnnotation注解!");//獲取該元素上指定類型的注解CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()+ ", score: " + cherryAnnotation.score()[0]);}else{System.out.println("Student類上沒有配置CherryAnnotation注解!");}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}
}
# 程序輸出
Student類上配置了CherryAnnotation注解!
name: cherry-peng, age: 23, score: 99
4.3 注解處理器類庫(java.lang.reflect.AnnotatedElement)
Java使用Annotation接口來代表程序元素前面的注解,該接口是所有Annotation類型的父接口。除此之外,Java
在java.lang.reflect
包下新增了AnnotatedElement
接口,該接口代表程序中可以接受注解的程序元素,該接
口主要有如下幾個實現(xiàn)類:
Class
:類定義
Constructor
:構(gòu)造器定義
Field
:類的成員變量定義
Method
:類的方法定義
Package
:類的包定義
java.lang.reflect
包下主要包含一些實現(xiàn)反射功能的工具類,實際上,java.lang.reflect 包所有提供的反射API
擴充了讀取運行時Annotation信息的能力。當(dāng)一個Annotation類型被定義為運行時的Annotation后,該注解才能
是運行時可見,當(dāng)class文件被裝載時被保存在class文件中的Annotation才會被虛擬機讀取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了
某個類的AnnotatedElement對象之后,程序就可以調(diào)用該對象的如下四個個方法來訪問Annotation信息:
isAnnotationPresent(Class<? extends Annotation> annotationClass)
方法是專門判斷該元素上是否配
置有某個指定的注解;
getAnnotation(Class<A> annotationClass)
方法是獲取該元素上指定的注解。之后再調(diào)用該注解的注解類型
元素方法就可以獲得配置時的值數(shù)據(jù);如果該類型注解不存在,則返回null。
反射對象上還有一個方法getAnnotations()
,該方法可以獲得該對象身上配置的所有的注解。它會返回給我們
一個注解數(shù)組,需要注意的是該數(shù)組的類型是Annotation類型,這個Annotation是一個來自于
java.lang.annotation
包的接口。
Annotation[] getDeclaredAnnotations()
:返回直接存在于此元素上的所有注解。與此接口中的其他方法不
同,該方法將忽略繼承的注解。(如果沒有注解直接存在于此元素上,則返回長度為零的一個數(shù)組)。該方法的調(diào)
用者可以隨意修改返回的數(shù)組;這不會對其它調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
如果我們要獲得的注解是配置在方法上的,那么我們要從Method對象上獲取;如果是配置在屬性上,就需要從該
屬性對應(yīng)的Field對象上去獲取,如果是配置在類型上,需要從Class對象上去獲取??傊谡l身上,就從誰身上去
獲取!
一個簡單的注解處理器
/***********注解聲明***************/package com.test2;import java.lang.annotation.*;/*** 水果名稱注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test2;import java.lang.annotation.*;/*** 水果顏色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 顏色枚舉** @author peida*/public enum Color {BULE, RED, GREEN};/*** 顏色屬性** @return*/Color fruitColor() default Color.GREEN;}
package com.test2;import java.lang.annotation.*;/*** 水果供應(yīng)者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供應(yīng)商編號** @return*/public int id() default -1;/*** 供應(yīng)商名稱** @return*/public String name() default "";/*** 供應(yīng)商地址** @return*/public String address() default "";
}
/***********注解使用***************/package com.test2;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(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("水果的名字是:蘋果");}
}
/***********注解處理器***************/package com.test2;import java.lang.reflect.Field;public class FruitInfoUtil {public static void getFruitInfo(Class<?> clazz) {String strFruitName = " 水果名稱:";String strFruitColor = " 水果顏色:";String strFruitProvicer = "供應(yīng)商信息:";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 = " 供應(yīng)商編號:" + fruitProvider.id() + " 供應(yīng)商名稱:" + fruitProvider.name() + " 供應(yīng)商地址:" + fruitProvider.address();System.out.println(strFruitProvicer);}}}
}
/***********輸出結(jié)果***************/package com.test2;public class FruitRun {/*** @param args*/public static void main(String[] args) {FruitInfoUtil.getFruitInfo(Apple.class);}}
# 程序輸出水果名稱:Apple水果顏色:RED供應(yīng)商編號:1 供應(yīng)商名稱:陜西紅富士集團 供應(yīng)商地址:陜西省西安市延安路89號紅富士大廈