黑馬程序員--Java學習日記之類的加載,反射,動態代理,枚舉


 

                                            ------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------


一、類的加載

1、類的加載相關概述

當程序要使用某個類時,如果該類還未被加載到內存中,則系統會通過加載、連接、初始化三步來對這個類進行初始化。

①加載

  • 就是指將class文件讀入內存,併爲之創建一個Class對象
  • 任何類被使用時系統都會建立一個Class對象。

②連接

  • 驗證 是否有正確的內部結構,並和其他類協調一致
  • 準備 負責爲類的靜態成員分配內存,並設置默認初始化值
  • 解析 將類的二進制數據中的符號引用替換爲直接引用
③初始化:跟以前的初始化動作一樣。

2、類加載器

①概念:負責將.class文件加載到內存中,併爲之生成對應的Class對象。

②類加載器的組成:

  • Bootstrap Classloader根類加載器。也稱爲引導類加載器負責java核心類的加載,比如System.String等。在JDK中JRE的lib目錄下rt.jar文件中。
  • Extension ClassLoader擴展類加載器。負責JRE的擴展目錄中jar包的加載,在JDK中JRE的lib目錄下的ext目錄。
  • System CkassLoader 系統類加載器,負責在JVM啓動時加載來自java命令的class文件,以及負責classpath環境變量所指定的jar包和路徑。主要是用來加載我們寫的文件。

二、反射

1、反射的基石——Class類

①所有的類文件都有共同屬性,所以可以向上抽取,把這些共性內容封裝成一個類,這個類就叫Class(描述字節碼文件的對象)。

  • Class類中就包含屬性有field(字段)、method(方法)、construction(構造函數)。
  • 而field中有修飾符、類型、變量名等複雜的描述內容,因此也可以將字段封裝稱爲一個對象。用來獲取類中field的內容,這個對象的描述叫Field。同理方法和構造函數也被封裝成對象Method、Constructor。要想對一個類進行內容的獲取,必須要先獲取該字節碼文件的對象。該對象是Class類型。
  • Class類描述的信息:類的名字,類的訪問屬性,類所屬於的包名,字段名稱的列表,方法名稱的列表等。每一個字節碼就是class的實例對象。如:classcls=Data.class;

②Class和class的區別

  • class:Java中的類用於描述一類事物的共性,該類事物有什麼屬性,沒有什麼屬性,至於這個屬性的值是什麼,則由此類的實例對象確定,不同的實例對象有不同的屬性值。
  • Class:指的是Java程序中的各個Java類是屬於同一類事物,都是Java程序的類,這些類稱爲Class。例如人對應的是Person類,Java類對應的就是Class。Class是Java程序中各個Java類的總稱;它是反射的基石,通過Class類來使用反射。

2、反射機制

JAVA反射機制是在運行狀態中,對於任意一個類,都能知道這個類的所有屬性和方法,對於任意一個對象,都能調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。簡而言之,反射就是通過class文件對象,去使用該文件中的成員變量,構造方法,成員方法。

要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用就是Class類中方法

獲取Class文件對象的方式:

①Object類的getClass()方法。獲取字節碼文件對象。

Personp = new Person();

Classc = p.getClass();

②數據類型的靜態屬性class:比第一種方式簡單,不用創建對象,也不會調用getClass方法,但是還是要使用具體的類對象和該類的一個靜態屬性完成。

Classc2 = Person.class;

③Class類中的靜態方法forName()方法。注意:要拿帶包名的全路徑名稱:這種方式比較簡單,不用創建對象,也不用調用方法,也不需要去調用具體的屬性和行爲,就能獲取到Class對象了。

Classc3 = Class.forName("Person");

一般我們到底使用哪種方法呢?

自己玩:任選一種,第二種較爲方便

開發:第三種。爲什麼呢?因爲第三種是一個字符串,而不是一個具體的類名,這樣我們就可以把這樣的字符串配置到配置文件中。

三種獲取Class文件對象的方式演示:



package cn.itcast_01;  
02.  
03./* 
04. *獲取Class文件對象的三種方式 
05. */  
06.public class ReflectDemo {  
07.    public static void main(String[] args) throws ClassNotFoundException {  
08.        //第一種  
09.        Person p = new Person();  
10.        Class c = p.getClass();  
11.  
12.        Person p2 = new Person();  
13.        Class c2 = p2.getClass();  
14.  
15.        System.out.println(p == p2);// false  
16.        System.out.println(c == c2);// true  
17.  
18.        //第二種  
19.        Class c3 = Person.class;  
20.        // int.class;  
21.        // String.class;  
22.        System.out.println(c == c3);  
23.  
24.        // 第三種  
25.        // ClassNotFoundException  
26.        Class c4 = Class.forName("cn.itcast_01.Person");  
27.        System.out.println(c == c4);  
28.    }  
29.}  

3、Class類中的常用方法

通過反射獲取和使用構造方法和類中成員變量即成員方法

①獲取構造方法

  • getConstructor(Class<?>... parameterTypes):返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構造方法。
  • getDeclaredConstructor(Class<?>... parameterTypes):返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構造方法。

②創建對象

  • newInstance():創建此 Class 對象所表示的類的一個新實例。

③獲取所有成員

  • getFields():返回一個包含某些 Field 對象的數組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。
  • getDeclaredFields():返回 Field 對象的一個數組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。

④獲取單個成員

  • getField(String name):返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。
  • getDeclaredField(String name):返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。

⑤獲取所有方法

  • getMethods():返回一個包含某些 Method 對象的數組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。
  • getDeclaredMethods(): 返回 Method 對象的一個數組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。

⑥獲取單個方法

  • getMethod(String name,Class<?>... parameterTypes): 返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。
  • getDeclaredMethod(String name,Class<?>... parameterTypes): 返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。

方法演示代碼如下:


package cn.itcast_02;  
02.  
03.import java.lang.reflect.Constructor;  
04.  
05.import cn.itcast_01.Person;  
06.  
07./* 
08. * 通過反射獲取構造方法並使用。 
09. */  
10.public class ReflectDemo {  
11.    public static void main(String[] args) throws Exception {  
12.        // 獲取字節碼文件對象  
13.        Class<?> c = Class.forName("cn.itcast_01.Person");  
14.  
15.        // 獲取構造方法  
16.        // public Constructor[] getConstructors():所有公共構造方法  
17.        // public Constructor[] getDeclaredConstructors():所有構造方法  
18.        Constructor<?> [] cons = c.getDeclaredConstructors();  
19.        for (Constructor<?> con : cons) {  
20.            System.out.println(con);  
21.        }  
22.  
23.        // 獲取單個構造方法  
24.        // public Constructor<T> getConstructor(Class<?>... parameterTypes)  
25.        // 參數表示的是:你要獲取的構造方法的構造參數個數及數據類型的class字節碼文件對象  
26.        Constructor<?> con = c.getConstructor();// 返回的是構造方法對象  
27.  
28.        Person p = new Person();  
29.        System.out.println(p);  
30.        // public T newInstance(Object... initargs)  
31.        // 使用此 Constructor 對象表示的構造方法來創建該構造方法的聲明類的新實例,  
32.        //並用指定的初始化參數初始化該實例。  
33.        Object obj = con.newInstance();  
34.        System.out.println(obj);  
35.  
36.        Person p1 = (Person) obj;  
37.        p1.show();  
38.    }  
39.}  

4、Constructor<T>類

①概述:當指定的類中沒有空參數構造函數時,或者創建的類對象需要通過指定的構造函數進行初始化,這時候就不能使用Class類中的newInstance方法。這時候我們就需要通過其它的方法來實現了。
②Constructor代表的是某個類的一個構造方法。提供關於類的單個構造方法的信息以及對它的訪問權限。
③獲取構造方法

  • 獲取所有的構造方法:Constructor[] cons = Class.forName(“cn.itheima.Person”).getConstructors();
  • 獲取單個構造方法:Constructor con=Person.class.getConstructor(String.class,int.class);

④創建實例對象

  • 反射方式:Person p= (Person)con.newInstance(“lisi”,30);
  • 通常方式:Person p = new Person(“lisi”,30);

注意:創建實例時newInstance方法中的參數列表必須與獲取Constructor的方法getConstructor方法中的參數列表一致。

5、Field類

①Field代表的是某個類的某個成員變量。
②方法:

  • Field getField(String s);只能獲取公有和父類中公有
  • Field getDeclaredField(String s);獲取該類中任意成員變量,包括私有
  • setAccessible(ture);如果是私有字段,要先將該私有字段進行取消權限檢查的能力。也稱暴力訪問。
  • set(Object obj, Object value);將指定對象變量上此Field對象表示的字段設置爲指定的新值。
  • Object get(Object obj);返回指定對象上Field表示的字段的值。



代碼演示如下:

package cn.itcast_03;  
02.  
03.import java.lang.reflect.Constructor;  
04.import java.lang.reflect.Field;  
05.  
06./* 
07. * 通過發生獲取成員變量並使用 
08. */  
09.public class ReflectDemo {  
10.    public static void main(String[] args) throws Exception {  
11.        // 獲取字節碼文件對象  
12.        Class<?> c = Class.forName("cn.itcast_01.Person");  
13.  
14.        // 獲取所有的成員變量  
15.        // Field[] fields = c.getFields();  
16.        // Field[] fields = c.getDeclaredFields();  
17.        // for (Field field : fields) {  
18.        // System.out.println(field);  
19.        // }  
20.  
21.        /* 
22.         * Person p = new Person(); p.address = "北京"; System.out.println(p); 
23.         */  
24.  
25.        // 通過無參構造方法創建對象  
26.        Constructor<?> con = c.getConstructor();  
27.        Object obj = con.newInstance();  
28.        System.out.println(obj);  
29.  
30.        // 獲取單個的成員變量  
31.        // 獲取address並對其賦值  
32.        Field addressField = c.getField("address");  
33.        // public void set(Object obj,Object value)  
34.        // 將指定對象變量上此 Field 對象表示的字段設置爲指定的新值。  
35.        addressField.set(obj, "北京"); // 給obj對象的addressField字段設置值爲"北京"  
36.        System.out.println(obj);  
37.  
38.        // 獲取name並對其賦值  
39.        // NoSuchFieldException  
40.        Field nameField = c.getDeclaredField("name");  
41.        // IllegalAccessException  
42.        nameField.setAccessible(true);  
43.        nameField.set(obj, "林青霞");  
44.        System.out.println(obj);  
45.  
46.        // 獲取age並對其賦值  
47.        Field ageField = c.getDeclaredField("age");  
48.        ageField.setAccessible(true);  
49.        ageField.set(obj, 27);  
50.        System.out.println(obj);  
51.    }  
52.}  

6、Method類

①概述:Method類代表類中的一個成員方法,調用某個對象身上的方法,要先得到方法,再針對某個對象調用。
②舉一個例子:獲得String類的charAt方法。
Method methodCharAt=Class.forName("java.lang.String").getMethod("charAt",int.class);
System.out.println(methodCharAt.invoke(str,1));//調用str對象中charAt(1)
③調用方法

  • 通常方式:System.out.println(str.charAt(1));
  • 反射方式:System.out.println(charAt.invoke(str,1));//str是一個對象,這裏str可以是null,說明invoke()方法是一個靜態方法。

④實例應用:用反射方式執行某個類中的main方法
a、目的:寫一個程序,這個程序能夠根據用戶提供的類名,去執行該類中的Main方法。
b、問題:啓動java程序的main方法的參數是一個字符串數組, 即public static void main(String[]args),通過反射方式來調用這個main方法時,按jdk1.5的語法,整個數組是一個參數,而jdk1.4的語法,數組的每個元素對應一個參數,當做把一個字符串數組作爲參數傳遞給invoke方法如何處理(注意兼容)。所以,在給main方法傳遞參數時,不能使用代碼mainMthod.invoke(null,newString[]{“xxxx”}),javac只把它當做JDK1.4的語法進行理解,。而不能把它當做JDK1.5的語法解釋,因此,會出現參數類型不對的問題。
c、解決辦法:

  • 方法一:mainMethod.invoke(null,newObject[]{new String[]{xxxx}});
  • 方法二:mainMethod.invoke)((Object)newString[]{"xxxx"});編譯器會做特殊處理,編譯時不把參數當做數組看待,也就不會數組達三成若干參數

實例一:Method方法演示


package cn.itcast_04;  
02.  
03.import java.lang.reflect.Constructor;  
04.import java.lang.reflect.Method;  
05.  
06.public class ReflectDemo {  
07.    public static void main(String[] args) throws Exception {  
08.        // 獲取字節碼文件對象  
09.        Class<?> c = Class.forName("cn.itcast_01.Person");  
10.  
11.        // 獲取所有的方法  
12.        // Method[] methods = c.getMethods(); // 獲取自己的包括父親的公共方法  
13.        // Method[] methods = c.getDeclaredMethods(); // 獲取自己的所有的方法  
14.        // for (Method method : methods) {  
15.        // System.out.println(method);  
16.        // }  
17.  
18.        Constructor<?> con = c.getConstructor();  
19.        Object obj = con.newInstance();  
20.  
21.        /* 
22.         * Person p = new Person(); p.show(); 
23.         */  
24.  
25.        // 獲取單個方法並使用  
26.        // public void show()  
27.        // public Method getMethod(String name,Class<?>... parameterTypes)  
28.        // 第一個參數表示的方法名,第二個參數表示的是方法的參數的class類型  
29.        Method m1 = c.getMethod("show");  
30.        // obj.m1(); // 錯誤  
31.        // public Object invoke(Object obj,Object... args)  
32.        // 返回值是Object接收,第一個參數表示對象是誰,第二參數表示調用該方法的實際參數  
33.        m1.invoke(obj); // 調用obj對象的m1方法  
34.  
35.        System.out.println("----------");  
36.        // public void method(String s)  
37.        Method m2 = c.getMethod("method", String.class);  
38.        m2.invoke(obj, "hello");  
39.        System.out.println("----------");  
40.  
41.        // public String getString(String s, int i)  
42.        Method m3 = c.getMethod("getString", String.class, int.class);  
43.        Object objString = m3.invoke(obj, "hello", 100);  
44.        System.out.println(objString);  
45.        // String s = (String)m3.invoke(obj, "hello",100);  
46.        // System.out.println(s);  
47.        System.out.println("----------");  
48.  
49.        // private void function()  
50.        Method m4 = c.getDeclaredMethod("function");  
51.        m4.setAccessible(true);  
52.        m4.invoke(obj);  
53.    }  
54.}  

實例二: 寫一個程序,這個程序能夠根據用戶提供的類名,去執行該類中的main方法。

package cn.itheima;  
02.//定義一個測試類  
03.class Test{  
04.    public static void main(String[] args){  
05.        for(String arg : args){  
06.            System.out.println(arg);  
07.        }  
08.    }  
09.}  
10.//用反射方式根據用戶提供的類名,去執行該類中的main方法。  
11.import java.lang.reflect.Method;  
12.  
13.public class PerformedMain{  
14.  
15.    public static void main(String[] args) throws Exception {  
16.        //普通方式  
17.        Test.main(new String[]{"123","456","789"});  
18.        System.out.println("-----------------------------");  
19.                  
20.        //反射方式  
21.        String className=args[0];  
22.        Class clazz=Class.forName(className);  
23.                  
24.        Method methodMain=clazz.getMethod("main",String[].class);  
25.        //方式一:強制轉換爲超類Object,不用拆包  
26.        methodMain.invoke(null, (Object)new String[]{"123","456","789"});  
27.        //方式二:將數組打包,編譯器拆包後就是一個String[]類型的整體   
28.        methodMain.invoke(null, new Object[]{new String[]{"123","456","789"}});  
29.    }  

三、數組的反射

①具有相同維數和元素類型的數組屬於同一個類型,即具有相同的Class實例對象。
②代表數組的Class實例對象的getSuperClass()方法,返回的父類爲Object類對應的Class
③基本類型的一維數組可以被當做Object類型使用,不能作爲Object[]類型使用,不能當做Object[]類型使用,非基本類型的一維數組,既可以當做Object類型使用,又可以當做Object[]類使用
④ 注意區別 Array.asList()方法處理int[]和String[]時的差異
⑤ Array工具類用於完成對數組的反射操作

  • Array.getLength(Object obj);獲取數組的長度
  •  Array.get(Object obj,int x);獲取數組中的元素

     四.反射的重要應用

1.通過反射運行配置文件的內容


public class Demo {  
02.    public static void main(String[] args) throws Exception{  
03.          
04.        /* 
05.        //獲取一個class類對象,使用三種方法中那一中,class類中靜態方法 
06.        Class aclass =Class.forName("cn.itcast.Test反射讀取配置文件.line2"); 
07.        //由獲得Class對象再得到一個該類的一個對象 
08.        Object obj=aclass.getConstructor().newInstance(); 
09.        //得到的該類的一個成員方法 
10.        Method m=aclass.getMethod("move", int.class); 
11.        m.invoke(obj, 20); 
12.        */  
13.          
14.        //定義一個class類對象  
15.        Class aclass=Class.forName(getvalue("classname"));  
16.        //通過反射,並調用構造方法,創建一個該類的對象  
17.        Object obj=aclass.getConstructor(String.class).newInstance("好方法");  
18.        //通過反射調用其成員方法  
19.        aclass.getMethod(getvalue("methodname"), int.class).invoke(obj, 50);          
20.    }  
21.    //通過定義一個方法來獲取幾種東西  
22.    public static String getvalue(String str)throws IOException{  
23.        //定義一個properties集合map集合,以便於讀寫文件  
24.        Properties pro=new Properties();  
25.        //定義一個輸入流  
26.        FileReader filein=new FileReader(new File("pro.properties"));  
27.        //讀取文件中內容到集合中  
28.        pro.load(filein);  
29.        //關閉資源  
30.        filein.close();       
31.        return pro.getProperty(str);  
32.    }  
33.}  
34.public class line2 {  
35.    private String name;  
36.    public line2(String name){  
37.        this.name =name;  
38.    }     
39.    public void move(int n){  
40.        System.out.println("名字是:"+name+"小夥的年齡是"+n);  
41.    }  
42.}  

2.通過泛型越過泛型檢查

泛型只是在編譯期間有作用,可以通過泛型直接加載其class,往聲明泛型的集合添加東西

public class Demo {  
02.    public static void main(String[] args) throws Exception  {  
03.        //定義一個集合  
04.        ArrayList<Integer> list=new ArrayList<>();  
05.        list.add(10);  
06.        //使用反射創建此類的class對象,調用其方法  
07.        Class aclass=ArrayList.class;//list.getclass();  
08.        //獲取其方法的對象,使用的參數爲object.class,通用的類型  
09.        Method m=aclass.getMethod("add", Object.class);  
10.        m.invoke(list, "nihaoma ");  
11.        System.out.println(list);  
12.    }  
13.}  


3.通過泛型設置某個對象的某個屬性爲指定值

public class Demo {  
02.    public static void main(String[] args) throws Exception {  
03.        Cat c=new Cat();  
04.        setValue(c,"name","bosimao");  
05.        setValue(c, "age", 2);  
06.        System.out.println("年齡:"+c.getAge()+"名字:"+c.getName());  
07.    }  
08.  
09.  
10.    private static void setValue(Object obj, String fieldName, Object value) throws Exception {  
11.        Class aclass=obj.getClass();  
12.        Field field=aclass.getDeclaredField(fieldName);  
13.        //由於是私有屬性,需要暴力訪問  
14.        field.setAccessible(true);  
15.        field.set( obj, value);  
16.    }     
17.}  
18.public class Cat {  
19.    private String name;  
20.    private int age=0;  
21.      
22.    public String getName(){  
23.        return this.name;  
24.    }  
25.    public int getAge(){  
26.        return this.age;  
27.    }  
28.}  

五.動態代理

1.動態代理的概述

本來應該自己做的事情,卻請了別人來做,被請的人就是代理對象。

在程序運行過程中產生的這個對象,而程序運行過程中產生對象其實就是我們剛纔反射講解的內容,所以,動態代理其實就是通過反射來生成一個代理

2.代理模式:

1).Student類中有一個coding()方法,寫程序;
2).測試類中如果需要coding()方法,需要直接實例化一個Student,並調用方法;
如果想在coding()方法的前面或者後面添加一些其他功能,可以不用修改Student類,而爲Student類添加
一個"代理類",代理類會調用Student類中的方法。
3).增加了代理類後,測試類不需要直接面對Student,轉而使用代理類。代理類中爲coding方法添加了新的功能。
實際上就是不直接使用基礎類,而是使用第三方代理,並且代理可以添加一些基本功能

public class Demo {//測試類  
02.    public static void main(String[] args) {  
03.        /* 
04.        Student stu = new Student(); 
05.        stu.coding(); 
06.        */  
07.        //使用代理模式  
08.        StudentProxy proxy = new StudentProxy();  
09.        proxy.coding();  
10.    }  
11.}  
12.  
13.  
14.  
15.  
16.public class StudentProxy {//代理類  
17.    public void coding(){  
18.        check();  
19.        new Student().coding();  
20.        zj();  
21.    }  
22.    //先期檢查  
23.    public void check(){  
24.        System.out.println("先期檢查......");  
25.    }  
26.    //後期總結  
27.    public void zj(){  
28.        System.out.println("後期總結.......");  
29.    }  
30.}  
31.  
32.  
33.  
34.  
35.public class Student {//基礎類  
36.    public void coding(){  
37.        System.out.println("做項目,寫程序......");  
38.    }  
39.}  

3.動態代理的步驟;

1).自定義一個類,實現InvocationHander接口,並重寫接口中的invoke()方法
2).在需要使用代理類的時候,使用Proxy類中的newProxyInstance()方法獲取代理類的對象
3).JDK只能爲接口做動態代理,所以要爲所要代理的類定義一個接口,並去實現接口

public class Demo {//測試類  
02.    public static void main(String[] args) throws Exception {  
03.        //多態的子類對象,使用proxy類中的方法newproxyInstace  
04.          
05.        //Idao idaostu=(Idao) Proxy.newProxyInstance(Class.forName("cn.itcast.Test動態代理.Student").getClassLoader(),   
06.        //                                  Student.class.getInterfaces(),new MyInvocationhander(new Student()));  
07.          
08.        Idao idaostu=(Idao) Proxy.newProxyInstance(Student.class.getClassLoader(),   
09.                                                    Student.class.getInterfaces(),  
10.                                                    new MyInvocationhander(new Student()));  
11.        idaostu.write();//需要使用的方法  
12.    }  
13.}  
14.  
15.  
16.  
17.  
18.public class MyInvocationhander implements InvocationHandler {//實現接口,代理類  
19.      
20.    private Object obj;//定義需要代理的對象  
21.    public MyInvocationhander(Object obj) {  
22.        this.obj=obj;  
23.    }  
24.  
25.  
26.    @Override  
27.    public Object invoke(Object proxy, Method method, Object[] args)  
28.            throws Throwable {  
29.        Object objmethod=method.invoke(obj);  
30.        show();  
31.        return objmethod;  
32.    }  
33.  
34.  
35.    private void show() {  
36.        System.out.println("真是牛叉啊!!");  
37.    }  
38.}  
39.  
40.  
41.public interface Idao {//自己定義接口  
42.    public void write();  
43.}  
44.  
45.  
46.public class Student implements Idao {//自定義類,需要代理的類  
47.          
48.    @Override  
49.    public void write() {  
50.        System.out.println("你好,動態代理!!");  
51.    }  
52.}  


六.枚舉

1.枚舉概述

一種模式"多例模式":在整個應用程序運行期間,有些類的實例,只允許有固定的幾個,這種模式就是"多例模式"
  例如:骰子:需要2個實例;
          撲克:54個實例;        
    現在說的枚舉,就是基於"多例模式":  
例如:我們的程序運行期間,需要三個顏色(紅\綠\藍),所以我們使用一個類MyColor來表示顏色。因爲我們只需要三個顏色,所以這個類的對象,只能有三個;

public abstract class MyColor3 {//抽象類也是可以定義多例模式  
02.    public static final MyColor3 RED  = new MyColor3("紅"){  
03.        @Override  
04.        void show() {  
05.            System.out.println("我是紅色的!");  
06.        }};  
07.    public static final MyColor3 GREEN = new MyColor3("綠"){  
08.        @Override  
09.        void show() {  
10.            System.out.println("我是綠色的!");  
11.        }};  
12.    public static final MyColor3 BLUE = new MyColor3("藍"){  
13.        @Override  
14.        void show() {  
15.            System.out.println("我是藍色的!");  
16.        }};  
17.    private String colorName;  
18.      
19.    private MyColor3(String colorName){  
20.        this.colorName = colorName;  
21.    }  
22.      
23.    public String toString(){  
24.        return this.colorName;  
25.    }  
26.      
27.    abstract void show();  
28.}  

2.製作枚舉步驟:

1).定義枚舉:public enum Xxxxx
2).直接定義枚舉項。注意:可以有其它成員,但枚舉項必須在第一行;
3).枚舉中可以包含抽象方法;
4).任何的枚舉類,都繼承自:Enum類;

public enum MyColor3 {  
02.    RED("紅") {  
03.        @Override  
04.        void show() {  
05.            System.out.println("我是紅色的!");  
06.        }  
07.    },GREEN("綠") {  
08.        @Override  
09.        void show() {  
10.            System.out.println("我是綠色的!");  
11.        }  
12.    },BLUE("藍") {  
13.        @Override  
14.        void show() {  
15.            System.out.println("我是藍色的!");  
16.        }  
17.    };  
18.    private String colorName;  
19.    private MyColor3(String n){  
20.        this.colorName = n;  
21.    }  
22.      
23.    public String getColorName(){  
24.        return this.colorName;  
25.    }  
26.      
27.    abstract void show();  
28.}  

3.枚舉類中常用方法,使用枚舉對象調用

int compareTo(E o)//比較的是枚舉項的索引值,做減法
String name()//枚舉項的名字fieldname
int ordinal()//枚舉項的索引值
String toString()//枚舉對象所對對應的fieldname
<T> T valueOf(Class<T> type,String name)//將一個字符串轉換爲type類型的對象
values() 
此方法雖然在JDK文檔中查找不到,但每個枚舉類都具有該方法,它遍歷枚舉類的所有枚舉值非常方便

public class Demo {  
02.    public static void main(String[] args) {  
03.        MyColor3 c1 = MyColor3.RED;  
04.        MyColor3 c2 = MyColor3.BLUE;  
05.          
06.        System.out.println(c2.compareTo(c1));//索引值的減法  
07.        System.out.println("name = " + c2.name());//BLUE  
08.        //int ordinal()  
09.        System.out.println("c2.ordinal() : " + c2.ordinal());  
10.        System.out.println("c1.ordinal() : " + c1.ordinal());  
11.        //String toString()  
12.        System.out.println("c2.toString():" + c2.toString());  
13.        //<T> T valueOf(Class<T> type,String name)  
14.        MyColor3 c3 = c1.valueOf("RED");//將一個字符串轉換爲MyColor3對象  
15.        MyColor3 c4 = MyColor3.valueOf(MyColor3.class,"BLUE");  
16.          
17.        System.out.println(c3);  
18.        System.out.println(c4);  
19.          
20.        //values()   
21.        MyColor3[] result = c1.values();  
22.        System.out.println("循環遍歷:");  
23.        for(MyColor3 c : result){  
24.            System.out.println(c);  
25.        }  
26.    }  
27.}  




                                                              ------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章