天天看點

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

文章目錄

  • ​​Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省​​
  • ​​1. 枚舉​​
  • ​​(1). 枚舉概述​​
  • ​​(2). 定義格式​​
  • ​​(3). 枚舉類的主要方法​​
  • ​​(4). 實作接口的枚舉類​​
  • ​​(5). 枚舉注意事項​​
  • ​​2. 注解​​
  • ​​(1). 簡介​​
  • ​​(2). 重點​​
  • ​​(3). 内置注解​​
  • ​​(4). 元注解​​
  • ​​(5). 自定義注解​​
  • ​​3. 反射​​
  • ​​(1). 概述​​
  • ​​(2). 類加載器​​
  • ​​(3). 所有類型的Class對象​​
  • ​​(4). 得到Class的幾種方式​​
  • ​​(5). 擷取Constructor​​
  • ​​(6). 擷取Method​​
  • ​​(7). 擷取Field​​
  • ​​(8). 擷取注解資訊​​
  • ​​4. 内省​​
  • ​​(1). JavaBean​​
  • ​​(2). Introspector​​
  • ​​(3). BeanInfo​​
  • ​​(4). MethodDescriptor​​
  • ​​(5). 示例​​
  • ​​5. 最後​​

1. 枚舉

(1). 枚舉概述

JDK1.5引入了新的類型:枚舉。

在JDK1.5 之前,我們定義常量都是: public static fianl… 。很難管理。

枚舉,可以把相關的常量分組到一個枚舉類型裡,而且枚舉提供了比常量更多的方法。

用于定義有限數量的一組同類常量,例如:

錯誤級别: 低、中、高、急

一年的四季: 春、夏、秋、冬

商品的類型: 美妝、手機、電腦、男裝、女裝…

在枚舉類型中定義的常量是該枚舉類型的執行個體。

(2). 定義格式

權限修飾符 enum 枚舉名稱 {

執行個體1,執行個體2,執行個體3,執行個體4;

}

(3). 枚舉類的主要方法

方法名稱 描述
values() 以數組形式傳回枚舉類型的所有成員
valueOf() 将普通字元串轉換為枚舉執行個體
compareTo() 比較兩個枚舉成員在定義時的順序
ordinal() 擷取枚舉成員的索引位置

建立時選擇枚舉:

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省
package com.xiaoyaoyou.day14;

public enum Level {
//    LOW(1), MEDIUM(50), HIGH(100);
//    private int levelValue;
//
//    private Level(int levelValue) {
//        this.levelValue = levelValue;
//    }
//
//    public int getLevelValue() {
//        return levelValue;
//    }
//
//    public void setLevelValue(int levelValue) {
//        this.levelValue = levelValue;
//    }

LOW, MEDIUM, HIGH;
}      
package com.xiaoyaoyou.day14;

public class EnumTest {
    public static void main(String[] args) {
        System.out.println(Level.LOW.compareTo(Level.HIGH));
        System.out.println(Level.LOW.compareTo(Level.MEDIUM));
        System.out.println(Level.HIGH.compareTo(Level.LOW));

        System.out.println(Level.LOW.name());
        System.out.println(Level.LOW.toString());
        System.out.println(Level.LOW.ordinal());

        Level x =  Enum.valueOf(Level.class, "LOW");
        System.out.println(x);
    }
}      

結果:

-2
-1
2
LOW
LOW
0
LOW      

(4). 實作接口的枚舉類

所有的枚舉都繼承自java.lang.Enum類。由于Java 不支援多繼承,是以枚舉對象不能再繼承其他類。

每個枚舉對象,都可以實作自己的抽象方法。

如下圖:

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省
package com.xiaoyaoyou.day14;

public interface LShow {
    void show();
}      
package com.xiaoyaoyou.day14;

public enum Level implements LShow {
//    LOW(1), MEDIUM(50), HIGH(100);
//    private int levelValue;
//
//    private Level(int levelValue) {
//        this.levelValue = levelValue;
//    }
//
//    public int getLevelValue() {
//        return levelValue;
//    }
//
//    public void setLevelValue(int levelValue) {
//        this.levelValue = levelValue;
//    }

    LOW{
    @Override
    public void show() {
        System.out.println("低級别");
    }
    },
    MEDIUM{
        @Override
        public void show() {
            System.out.println("中級别");
        }
    },
    HIGH{
        @Override
        public void show() {
            System.out.println("進階别");
        }
    };
}      
package com.xiaoyaoyou.day14;

public class EnumTest {
    public static void main(String[] args) {
        System.out.println(Level.LOW.compareTo(Level.HIGH));
        System.out.println(Level.LOW.compareTo(Level.MEDIUM));
        System.out.println(Level.HIGH.compareTo(Level.LOW));

        System.out.println(Level.LOW.name());
        System.out.println(Level.LOW.toString());
        System.out.println(Level.LOW.ordinal());

        Level x =  Enum.valueOf(Level.class, "LOW");
        System.out.println(x);

        Level.LOW.show();
        Level.MEDIUM.show();
        Level.HIGH.show();
    }
}      

結果:

-2
-1
2
LOW
LOW
0
LOW
低級别
中級别
進階别      

(5). 枚舉注意事項

  • 一旦定義了枚舉,最好不要妄圖修改裡面的值,除非修改是必要的。
  • 枚舉類預設繼承的是java.lang.Enum類而不是Object類
  • 枚舉類不能有子類,因為其枚舉類預設被final修飾
  • 隻能有private構造方法
  • switch中使用枚舉時,直接使用常量名,不用攜帶類名
  • 不能定義name屬性,因為自帶name屬性
  • 不要為枚舉類中的屬性提供set方法,不符合枚舉最初設計初衷。

2. 注解

(1). 簡介

Java 注解(Annotation)又稱 Java 标注,是 JDK5.0 引入的一種注釋機制。

Java語言中的類、方法、變量、參數和包等都可以被标注。和注釋不同,Java标注可以通過反射擷取标注内容。在編譯器生成類檔案時,标注可以被嵌入到位元組碼中。Java 虛拟機可以保留标注内容,在運作時可以擷取到标注内容。當然它也支援自定義 Java 标注。

主要用于:

  • 編譯格式檢查
  • 反射中解析
  • 生成幫助文檔
  • 跟蹤代碼依賴等

(2). 重點

  1. 概念
  2. 怎麼使用内置注解
  3. 怎麼定義注解
  4. 反射中怎麼擷取注解内容

(3). 内置注解

  • @Override : 重寫 *
  • 定義在java.lang.Override
  • @Deprecated:廢棄 *
  • 定義在java.lang.Deprecated
  • @SafeVarargs
  • Java 7 開始支援,忽略任何使用參數為泛型變量的方法或構造函數調用産生的警告。
  • @FunctionalInterface: 函數式接口 *
  • Java 8 開始支援,辨別一個匿名函數或函數式接口。
  • @Repeatable:辨別某注解可以在同一個聲明上使用多次
  • Java 8 開始支援,辨別某注解可以在同一個聲明上使用多次。
  • @SuppressWarnings:抑制編譯時的警告資訊。 *
  • 定義在java.lang.SuppressWarnings
  • 三種使用方式
1. @SuppressWarnings("unchecked") [^ 抑制單類型的警告] 
2. @SuppressWarnings("unchecked","rawtypes") [^ 抑制多類型的警告] 
3. @SuppressWarnings("all") [^ 抑制所有類型的警告]      
  • 參數清單
Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

我們剛學習了proto buf,發現proto的設計和注解有很多類似之處,也可以看出來這些語言文法的設計都是為了解決問題而産生的,是以如果你發現了一個問題,就可以嘗試看下是否有解決該問題的方案,如果沒有,我們能否自己解決該問題那,解決後是否可開源出來?

(4). 元注解

含義:作用在其他注解的注解(需要結合自定義注解了解)

  • @Retention - 辨別這個注解怎麼儲存,是隻在代碼中,還是編入class檔案中,或者是在運作時可以通過反射通路。
  • @Documented - 标記這些注解是否包含在使用者文檔中 javadoc。
  • @Target - 标記這個注解應該是哪種 Java 成員。
  • @Inherited - 标記這個注解是自動繼承的
1. 子類會繼承父類使用的注解中被@Inherited修飾的注解
2. 接口繼承關系中,子接口不會繼承父接口中的任何注解,不管父接口中使用的注解有沒有被@Inherited修飾
3. 類實作接口時不會繼承任何接口中定義的注解      

(5). 自定義注解

  1. 注解架構
Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省
  • (1) Annotation與RetentionPolicy與ElementType

    每1個 Annotation 對象,都會有唯一的 RetentionPolicy 屬性;至于 ElementType 屬性,則有 1~n個。

  • (2) ElementType(注解的用途類型)

    “每 1 個 Annotation” 都與 “1~n 個 ElementType” 關聯。當 Annotation 與某個ElementType關聯時,就意味着:Annotation有了某種用途。例如,若一個 Annotation 對象是 METHOD 類型,則該Annotation 隻能用來修飾方法。

package java.lang.annotation;
public enum ElementType {
    TYPE, /* 類、接口(包括注釋類型)或枚舉聲明 */
    FIELD, /* 字段聲明(包括枚舉常量) */
    METHOD, /* 方法聲明 */
    PARAMETER, /* 參數聲明 */
    CONSTRUCTOR, /* 構造方法聲明 */
    LOCAL_VARIABLE, /* 局部變量聲明 */
    ANNOTATION_TYPE, /* 注釋類型聲明 */
    PACKAGE /* 包聲明 */
}      
  • (3) RetentionPolicy(注解作用域政策)

    “每 1 個 Annotation” 都與 “1 個 RetentionPolicy” 關聯。

    a) 若 Annotation 的類型為 SOURCE,則意味着:Annotation 僅存在于編譯器處理期間,編譯器處理完之後,該 Annotation 就沒用了。 例如," @Override" 标志就是一個 Annotation。當它修飾一個方法的時候,就意味着該方法覆寫父類的方法;并且在編譯期間會進行文法檢查!編譯器處理完後,"@Override" 就沒有任何作用了。

    b) 若 Annotation 的類型為 CLASS,則意味着:編譯器将 Annotation 存儲于類對應的 .class 檔案中,它是 Annotation 的預設行為。

    c) 若 Annotation 的類型為 RUNTIME,則意味着:編譯器将 Annotation 存儲于 class 檔案中,并且可由JVM讀入。

package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE, /* Annotation資訊僅存在于編譯器處理期間,編譯器處理完之後就沒有該 Annotation資訊了 */
    CLASS, /* 編譯器将Annotation存儲于類對應的.class檔案中。預設行為 */
    RUNTIME /* 編譯器将Annotation存儲于class檔案中,并且可由JVM讀入 */
}      
  1. 定義格式

@interface 自定義注解名{}

  1. 注意事項
  • 定義的注解,自動繼承了java.lang,annotation.Annotation接口
  • 注解中的每一個方法,實際是聲明的注解配置參數
  • 方法的名稱就是配置參數的名稱
  • 方法的傳回值類型,就是配置參數的類型,隻能是:基本類型/Class/String/enum
  • 可以通過default來聲明參數的預設值
  • 如果隻有一個參數成員,一般參數名為value
  • 注解元素必須要有值,我們定義注解元素時,經常使用空字元串、0作為預設值。
  1. 案例
package com.xiaoyaoyou.day14;

import java.lang.annotation.*;

@MyAnnotation("測試自定義注解")
public class InterfaceTest {
    public static void main(String[] args) {

    }
}

@Documented
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyAnnotation {
    String value() default "";
    int num() default 0;
}      

等到學完反射後看注解如何擷取注解内容。

3. 反射

(1). 概述

JAVA反射機制是在運作狀态中,擷取任意一個類的結構 , 建立對象 , 得到方法,執行方法 , 屬性 !

這種在運作狀态動态擷取資訊以及動态調用對象方法的功能被稱為java語言的反射機制,反射被視為動态語言的關鍵。

(2). 類加載器

Java類加載器(Java Classloader)是Java運作時環境(Java Runtime Environment)的一部分, 負責動态加載Java類到Java虛拟機的記憶體空間中。

java預設有三種類加載器,BootstrapClassLoader、ExtensionClassLoader、App ClassLoader。

BootstrapClassLoader(引導啟動類加載器):嵌在JVM核心中的加載器,該加載器是用C++語言寫的,主要負載加載JAVA_HOME/lib下的類庫,引導啟動類加載器無法被應用程式直接使用。

ExtensionClassLoader(擴充類加載器): ExtensionClassLoader是用JAVA編寫,且它的父類加載器是Bootstrap。

是由sun.misc.Launcher$ExtClassLoader實作的,主要加載JAVA_HOME/lib/ext目錄中的類庫。

它的父加載器是BootstrapClassLoader

App ClassLoader(應用類加載器):App ClassLoader是應用程式類加載器,負責加載應用程式classpath目錄下的所有jar和class檔案。它的父加載器為Ext ClassLoader

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

類通常是按需加載,即第一次使用該類時才加載。由于有了類加載器,Java運作時系統不需要知道檔案與 檔案系統。學習類加載器時,掌握Java的委派概念很重要。

雙親委派模型:如果一個類加載器收到了一個類加載請求,它不會自己去嘗試加載這個類,而是把這個請求 轉交給父類加載器去完成。每一個層次的類加載器都是如此。是以所有的類加載請求都應該傳遞到最頂層的 啟動類加載器中,隻有到父類加載器回報自己無法完成這個加載請求(在它的搜尋範圍沒有找到這個類)時,子類加載器才會嘗試自己去加載。委派的好處就是避免有些類被重複加載。

加載配置檔案,給項目添加resource root目錄:

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

漢化後:

Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

代碼示例:

package com.xiaoyaoyou.day14;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

public class LoadResourceTest {
    public static void main(String[] args) throws IOException {
        InputStream inputStream = LoadResourceTest.class.getClassLoader().getResourceAsStream("config.txt");
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
        String text = bufferedReader.readLine();
        System.out.println(text);
        bufferedReader.close();
    }
}      

結果:

測試類加載器      
Java從入門到實戰總結-3.8、Java枚舉、注解、反射、内省

(3). 所有類型的Class對象

要想了解一個類,必須先要擷取到該類的位元組碼檔案對象.

在Java中,每一個位元組碼檔案,被夾在到記憶體後,都存在一個對應的Class類型的對象

(4). 得到Class的幾種方式

  • 如果在編寫代碼時, 知道類的名稱, 且類已經存在, 可以通過​

    ​包名.類名.class​

    ​得到一個類的類對象
  • 如果擁有類的對象, 可以通過​

    ​Class 對象.getClass()​

    ​得到一個類的類對象
  • 如果在編寫代碼時,知道類的名稱,可以通過​

    ​Class.forName(包名+類名)​

    ​:得到一個類的類對象

上述的三種方式, 在調用時, 如果類在記憶體中不存在, 則會加載到記憶體!如果類已經在記憶體中存在, 不會重複加載, 而是重複利用!

(一個class檔案 在記憶體中不會存在兩個類對象 )

特殊的類對象

  • 基本資料類型的類對象:

    基本資料類型.clss

    包裝類.type

  • 基本資料類型包裝類對象:

    包裝類.class

示例:

package com.xiaoyaoyou.day14;

public class GetClassTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //第一種,通過包名.類名.class加載類
        Class c1 = com.xiaoyaoyou.day14.LoadResourceTest.class;
        System.out.println(c1);

        //第二種,通過類的對象過去類的資訊
        LoadResourceTest loadResourceTest = new LoadResourceTest();
        Class c2 = loadResourceTest.getClass();
        System.out.println(c2);

        //第三種方式
        Class c3 = Class.forName("com.xiaoyaoyou.day14.LoadResourceTest");
        System.out.println(c3);
        System.out.println(c1==c2 && c1==c3);
    }
}      

結果:

class com.xiaoyaoyou.day14.LoadResourceTest
class com.xiaoyaoyou.day14.LoadResourceTest
class com.xiaoyaoyou.day14.LoadResourceTest
true      

(5). 擷取Constructor

  1. 通過擷取class對象擷取一個類的構造方法
  • (1). 通過指定的參數類型, 擷取指定的單個構造方法 getConstructor(參數類型的class對象數組)

    例如:構造方法如下: Person(String name,int age)

    得到這個構造方法的代碼如下:

    Constructor c = p.getClass().getConstructor(String.class,int.class);

  • (2). 擷取構造方法數組

    getConstructors();

  • (3). 擷取所有權限的單個構造方法

    getDeclaredConstructor(參數類型的class對象數組)

  • (4). 擷取所有權限的構造方法數組 getDeclaredConstructors();
  1. Constructor 建立對象
  • 常用方法: newInstance(Object… para)

    調用這個構造方法, 把對應的對象建立出來

    參數: 是一個Object類型可變參數,傳遞的參數順序必須比對構造方法中形式參數清單的順序!

  • setAccessible(boolean flag) 如果flag為true 則表示忽略通路權限檢查 !(可以通路任何權限的方法)
package com.xiaoyaoyou.day14;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class GetConstructorTest {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class c1 = Class.forName("com.xiaoyaoyou.day14.LoadResourceTest");
        Constructor c2 = c1.getConstructor();
        LoadResourceTest loadResourceTest = (LoadResourceTest) c2.newInstance();
        System.out.println(loadResourceTest.toString());
    }
}      

結果:

LoadResourceTest{}      

其它的方法和方式可以自己嘗試一下(忽略權限檢查的接口一定要試試)。

(6). 擷取Method

  1. 通過class對象 擷取一個類的方法
  • getMethod(String methodName , class… clss)

    根據參數清單的類型和方法名, 得到一個方法(public修飾的)

  • getMethods();

    得到一個類的所有方法 (public修飾的)

  • getDeclaredMethod(String methodName , class… clss)

    根據參數清單的類型和方法名, 得到一個方法(除繼承以外所有的:包含私有, 共有, 保護, 預設)

  • getDeclaredMethods();

    得到一個類的所有方法 (除繼承以外所有的:包含私有, 共有, 保護, 預設)

  1. Method 執行方法
  • invoke(Object o,Object… para):

    調用方法,

    參數1. 要調用方法的對象

    參數2. 要傳遞的參數清單

  • getName()

    擷取方法的方法名稱

  • setAccessible(boolean flag)

    如果flag為true 則表示忽略通路權限檢查 !(可以通路任何權限的方法)

(7). 擷取Field

  1. 通過class對象 擷取一個類的屬性
  • getDeclaredField(String filedName)

    根據屬性的名稱, 擷取一個屬性對象 (所有屬性)

  • getDeclaredFields()

    擷取所有屬性(屬性私有時需要配合忽略權限檢查使用)

  • getField(String filedName)

    根據屬性的名稱, 擷取一個屬性對象 (public屬性)

  • getFields()

    擷取所有屬性 (public)

  1. Field 屬性的對象類型

    常用方法:

  • get(Object o );

    參數: 要擷取屬性的對象 擷取指定對象的此屬性值

  • set(Object o , Object value);

    參數1. 要設定屬性值的對象

    參數2. 要設定的值

    設定指定對象的屬性的值

  • getName()

    擷取屬性的名稱

  • setAccessible(boolean flag)

    如果flag為true則表示忽略通路權限檢查!(可以通路任何權限的屬性)

(8). 擷取注解資訊

  1. 擷取類/屬性/方法的全部注解對象
Annotation[] annotations01 = Class/Field/Method.getAnnotations();

for (Annotation annotation : annotations01) {
    System.out.println(annotation);
}      
  1. 根據類型擷取類/屬性/方法的注解對象

注解類型 對象名 = (注解類型) c.getAnnotation(注解類型.class);

示例:

package com.xiaoyaoyou.day14;

import java.lang.annotation.Annotation;

public class GetAnnotationTest {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("com.xiaoyaoyou.day14.InterfaceTest");
        Annotation[] annotations = c.getAnnotations();
        for (Annotation a: annotations) {
            System.out.println(a);
        }

        MyAnnotation myAnnotation = (MyAnnotation) c.getAnnotation(MyAnnotation.class);
        System.out.println(myAnnotation.value());
        System.out.println(myAnnotation.num());
    }
}      

結果:

@com.xiaoyaoyou.day14.MyAnnotation(value=測試自定義注解, num=0)      

還可以擴充對類的屬性、方法等增加注解,然後通過擷取屬性、擷取方法的注解來做一些關聯操作。

4. 内省

(1). JavaBean

基于反射,java所提供的一套應用到JavaBean的API

一個定義在包中的類:

  • 擁有無參構造器
  • 所有屬性私有
  • 所有屬性提供get/set方法
  • 實作了序列化接口

這種類, 我們稱其為bean類.

Java提供了一套java.beans包的api,對于反射的操作, 進行了封裝!

(2). Introspector

擷取Bean類資訊

方法:

BeanInfo getBeanInfo(Class cls)

通過傳入的類資訊, 得到這個Bean類的封裝對象

(3). BeanInfo

常用的方法:

MethodDescriptor[] getPropertyDescriptors():

擷取bean類的 get/set方法 數組

(4). MethodDescriptor

常用方法:

  1. Method getReadMethod();擷取一個get方法
  2. Method getWriteMethod(); 擷取一個set方法 有可能傳回null 注意加判斷

(5). 示例

我們之前寫快遞E棧項目的時候接觸過bean,後續的架構學習還會接觸,這裡我們也主要學會使用了解一些概念即可,随着接觸更多的架構和項目對bean的了解會逐漸加深。

package com.xiaoyaoyou.day14;

import java.io.Serializable;

public class Express implements Serializable {
    private String name;
    private String number;
    private String phoneNumber;
    private String address;

    public Express() {
    }

    @Override
    public String toString() {
        return "Express{" +
                "name='" + name + '\'' +
                ", number='" + number + '\'' +
                ", phoneNumber='" + phoneNumber + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getPhoneNumber() {
        return phoneNumber;
    }

    public void setPhoneNumber(String phoneNumber) {
        this.phoneNumber = phoneNumber;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}      
package com.xiaoyaoyou.day14;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

public class BeanTest {
    public static void main(String[] args) throws IntrospectionException {
        Class c = Express.class;
        BeanInfo beanInfo = Introspector.getBeanInfo(c);
        PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor p:propertyDescriptors) {
            Method get = p.getReadMethod();
            Method set = p.getWriteMethod();
            System.out.println(get);
            System.out.println(set);
            System.out.println(p.getName());
            System.out.println(p.getPropertyType());
        }
    }
}      

結果:

public java.lang.String com.xiaoyaoyou.day14.Express.getAddress()
public void com.xiaoyaoyou.day14.Express.setAddress(java.lang.String)
address
class java.lang.String
public final native java.lang.Class java.lang.Object.getClass()
null
class
class java.lang.Class
public java.lang.String com.xiaoyaoyou.day14.Express.getName()
public void com.xiaoyaoyou.day14.Express.setName(java.lang.String)
name
class java.lang.String
public java.lang.String com.xiaoyaoyou.day14.Express.getNumber()
public void com.xiaoyaoyou.day14.Express.setNumber(java.lang.String)
number
class java.lang.String
public java.lang.String com.xiaoyaoyou.day14.Express.getPhoneNumber()
public void com.xiaoyaoyou.day14.Express.setPhoneNumber(java.lang.String)      

5. 最後