1. 程式人生 > >java enum 單例,工廠,多型

java enum 單例,工廠,多型

使用者自定義enum本質上是一個extends Enum的型別, Enum是一個抽象類,它的建構函式是private 型別的。

列舉中的例項相當於new了該列舉型別的例項,因為構造方法是private型別的,所以列舉型別在類內部例項化了若干個個具體的例項。

所以列舉類包含了3中設計模式:單例 + 工廠 + 多型(策略)

發現一篇好文章,講的比較清楚,特再轉如下:http://pf-miles.iteye.com/blog/187155

Enum+多型,我沒說錯,不過Enum是不可以被繼承的,也不可以繼承自別人,只是能實現介面而已,何談多型? 

不過還是先看看“現象”吧: 
Java程式碼  收藏程式碼
  1. public
     enum Fruit {  
  2.     APPLE, PEAR, PEACH, ORANGE;  
  3. }  

以上是一個簡單的enum,關於它,我要補充一點: 
Fruit是java.lang.Enum的子類,準確地說,是Enum<Fruit>的子類,這裡出現了一個繼承關係,不過這個繼承是編譯器幫我們做的,我們不能顯式地去做。不信的話我們可以試著用一個Enum<Fruit>的引用去指向一個APPLE,肯定是沒問題的,我就不再試了。 
為了更直觀地說明這一點,我們來看看Fruit的反編譯結果吧: 
Java程式碼  收藏程式碼
  1. package test;  
  2. public final
     class Fruit extends Enum  
  3. {  
  4.     private Fruit(String s, int i)  
  5.     {  
  6.         super(s, i);  
  7.     }  
  8.     public static Fruit[] values()  
  9.     {  
  10.         Fruit afruit[];  
  11.         int i;  
  12.         Fruit afruit1[];  
  13.         System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0
    , i);  
  14.         return afruit1;  
  15.     }  
  16.     public static Fruit valueOf(String s)  
  17.     {  
  18.         return (Fruit)Enum.valueOf(test/Fruit, s);  
  19.     }  
  20.     public static final Fruit APPLE;  
  21.     public static final Fruit PEAR;  
  22.     public static final Fruit PEACH;  
  23.     public static final Fruit ORANGE;  
  24.     private static final Fruit ENUM$VALUES[];  
  25.     static   
  26.     {  
  27.         APPLE = new Fruit("APPLE"0);  
  28.         PEAR = new Fruit("PEAR"1);  
  29.         PEACH = new Fruit("PEACH"2);  
  30.         ORANGE = new Fruit("ORANGE"3);  
  31.         ENUM$VALUES = (new Fruit[] {  
  32.             APPLE, PEAR, PEACH, ORANGE  
  33.         });  
  34.     }  
  35. }  

注意這幾行: 
Java程式碼  收藏程式碼
  1. public static final Fruit APPLE;  
  2.     public static final Fruit PEAR;  
  3.     public static final Fruit PEACH;  
  4.     public static final Fruit ORANGE;  

看來JDK Enum的實現也不過就是沿襲了Effective Java中提出的TypeSafeEnum模式,只不過是在編譯器和JVM等更底層的級別上提供了支援。 

至此,至少說明了Fruit和Enum的繼承關係,但問題是:現在不能繼續再從Fruit派生子類,那麼哪來的多型呢?

還是再多寫點程式碼吧: 
Java程式碼  收藏程式碼
  1. public enum Fruit {  
  2.     APPLE {  
  3.         public void test() {  
  4.             System.out.println("I am an apple.");  
  5.         }  
  6.     },  
  7.     PEAR {  
  8.         public void test() {  
  9.             System.out.println("I am a pear.");  
  10.         }  
  11.     },  
  12.     PEACH {  
  13.         public void test() {  
  14.             System.out.println("I am a peach.");  
  15.         }  
  16.     },  
  17.     ORANGE;  
  18.     public void test() {  
  19.         System.out.println("I am a fruit.");  
  20.     }  
  21. }  

其中,只有Orange沒有Overide test()方法; 
我們在主函式中呼叫它們: 
Java程式碼  收藏程式碼
  1. public static void main(String[] args) {  
  2.         Fruit.APPLE.test();  
  3.         Fruit.PEAR.test();  
  4.         Fruit.PEACH.test();  
  5.         Fruit.ORANGE.test();  
  6.     }  

輸出結果: 
引用 I am an apple. 
I am a pear. 
I am a peach. 
I am a fruit.
可以看到,重新定義了test方法的APPLE,PEAR,PEACH覆蓋了從父類繼承過來的預設行為,而未從新定義test方法的ORANGE卻沿襲了父類的行為,多型性在這裡展現出來了。 

那麼我們剛才明明看見過Fruit的反編譯結果,沒有任何新類繼承自Fruit,那麼這些多型行為是哪裡冒出來的呢?說它是“多型”是否準確呢? 
其實,Fruit類在這個時候已經發生了微妙的變化,一切都與JDK的Enum的實現有關,我們現在可以到編譯結果目錄下面看看: 

怎麼除了Fruit.class之外,還多了幾個貌似是內部類的class檔案??也許看到這裡我們能有點線索了,不過還是在這個時候在看看反編譯結果吧,看看它到底在搞什麼鬼: 
Java程式碼  收藏程式碼
  1. // Decompiled by Jad v1.5.8e. Copyright 2001 Pavel Kouznetsov.  
  2. // Jad home page: http://www.geocities.com/kpdus/jad.html  
  3. // Decompiler options: packimports(3)   
  4. // Source File Name:   Fruit.java  
  5. package test;  
  6. import java.io.PrintStream;  
  7. public class Fruit extends Enum  
  8. {  
  9.     private Fruit(String s, int i)  
  10.     {  
  11.         super(s, i);  
  12.     }  
  13.     public void test()  
  14.     {  
  15.         System.out.println("I am a fruit.");  
  16.     }  
  17.     public static Fruit[] values()  
  18.     {  
  19.         Fruit afruit[];  
  20.         int i;  
  21.         Fruit afruit1[];  
  22.         System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i);  
  23.         return afruit1;  
  24.     }  
  25.     public static Fruit valueOf(String s)  
  26.     {  
  27.         return (Fruit)Enum.valueOf(test/Fruit, s);  
  28.     }  
  29.     Fruit(String s, int i, Fruit fruit)  
  30.     {  
  31.         this(s, i);  
  32.     }  
  33.     public static final Fruit APPLE;  
  34.     public static final Fruit PEAR;  
  35.     public static final Fruit PEACH;  
  36.     public static final Fruit ORANGE;  
  37.     private static final Fruit ENUM$VALUES[];  
  38.     static   
  39.     {  
  40.         APPLE = new Fruit("APPLE"0) {  
  41.             public void test()  
  42.             {  
  43.                 System.out.println("I am an apple.");  
  44.             }  
  45.         };  
  46.         PEAR = new Fruit("PEAR"1) {  
  47.             public void test()  
  48.             {  
  49.                 System.out.println("I am a pear.");  
  50.             }  
  51.         };  
  52.         PEACH = new Fruit("PEACH"2) {  
  53.             public void test()  
  54.             {  
  55.                 System.out.println("I am a peach.");  
  56.             }  
  57.         };  
  58.         ORANGE = new Fruit("ORANGE"3);  
  59.         ENUM$VALUES = (new Fruit[] {  
  60.             APPLE, PEAR, PEACH, ORANGE  
  61.         });  
  62.     }  
  63. }  

注意這段程式碼: 
Java程式碼  收藏程式碼
  1. static   
  2.     {  
  3.         APPLE = new Fruit("APPLE"0) {  
  4.             public void test()  
  5.             {  
  6.                 System.out.println("I am an apple.");  
  7.             }  
  8.         };  
  9.         PEAR = new Fruit("PEAR"1) {  
  10.             public void test()  
  11.             {  
  12.                 System.out.println("I am a pear.");  
  13.             }  
  14.         };  
  15.         PEACH = new Fruit("PEACH"2) {  
  16.             public void test()  
  17.             {  
  18.                 System.out.println("I am a peach.");  
  19.             }  
  20.         };  
  21.         ORANGE = new Fruit("ORANGE"3);  

這個時候的APPLE,PEAR,PEACH已經以匿名內部類的方式對Fruit進行了Overide,自然體現出了多型,多出的那三個疑似內部類的class檔案也就是它們!而ORANGE,沒有重寫test方法,仍然以一個Fruit例項的形式出現。 

關於Enum為什麼會有多型大概也就這麼點貓膩了,那我們來考慮一下它有多大價值吧? 

我們或許可以利用這一點來改造Strategy模式,傳統的Strategy會產生出稍微多一些的父類、子類,而如果用Enum的話,“一個類”(對程式作者來講)就能搞定,能簡化一下類層次,再說了,用列舉來表示區分各種不同策略也是很合情理的,所以,Java Enum的這點小小特性感覺還是比較有前途發揮一些作用的,起碼在程式碼組織上;
更多應用可能或是侷限性就還需要逐步在實際應用中摸索。

相關推薦

java enum 工廠

使用者自定義enum本質上是一個extends Enum的型別, Enum是一個抽象類,它的建構函式是private 型別的。 列舉中的例項相當於new了該列舉型別的例項,因為構造方法是private型別的,所以列舉型別在類內部例項化了若干個個具體的例項。 所以列舉類包含了

Java設計模式餓漢式和懶漢式

set tin desc 驅動 ack 情況下 zed 獲取 java反射機制   Java中單例模式是一種常見的設計模式,單例模式的寫法有好幾種,這裏主要介紹三種:懶漢式單例、餓漢式單例、登記式單例。  單例模式有以下特點:  1、單例類只能有一個實例。  2、單例類必須

Java——執行緒基本使用(三) 餓漢式和懶漢式的設計模式執行緒之間的通訊

這一則部落格主要寫的是單例設計模式,與實現多執行緒之間的通訊等等~ 1.單例設計模式:保證類在記憶體中只有一個物件 2.保證類在記憶體中只有一個物件            &

JAVA】基礎:設計模式(設計模式工廠設計模式)

設計模式:解決某一類問題最行之有效的方法。 java中有23種設計模式。 建立型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。 結構型模式(7種):介面卡模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。 行為型模式(11種):策略模式、模板方法

spring bean的的使用場景和在bean中注入(不看後悔一看必懂)

為什麼用單例或者多例?何時用? 之所以用單例,是因為沒必要每個請求都新建一個物件,這樣子既浪費CPU又浪費記憶體; 之所以用多例,是為了防止併發問題;即一個請求改變了物件的狀態,此時物件又處理另一個請求,而之前請求對物件狀態的改變導致了物件對另一個請求做了錯誤的處理;  

java模式為什麼需要volatile及靜態內部類

目前看了java併發的書,記錄一下。對於java的單例模式,正確的程式碼應該為: public class TestInstance { private volatile static TestInstance instance; public st

java設計模式之設計模式這樣設計才最好!

單例模式,顧名思義只有一個例項,該中設計模式主要應用的場景如下: 1.需要頻繁例項化然後銷燬的物件。 2.建立物件時耗時過多或者耗資源過多,但又經常用到的物件。 3.完全限制需要單一物件的,例如計數器等等。 單例模式 一、用類圖表示單例模式如下: 二、常見的幾種單例模式

工廠模式加管理Fragment同時解決fragment切換資料丟失問題

package com.itjfr.jfr.fragment; import java.util.ArrayList; import java.util.List; import android.support.v4.app.Fragment; import andr

Java實現模式之餓漢式、懶漢式、列舉式帶測試。

Java實現單例的3種普遍的模式,餓漢式、懶漢式、列舉式。 具體程式碼如下: package com.lcx.mode; /** * * 餓漢式單例,不管以後用不用這個物件,我們一開始就建立這個物件的例項, * 需要的時候就返回已建立好的例項物件,所以比較飢餓,

java的區別

單例 多例 區別 線程 1. 什麽是單例多例:所謂單例就是所有的請求都用一個對象來處理,比如我們常用的service和dao層的對象通常都是單例的,而多例則指每個請求用一個新的對象來處理,比如action; 2. 如何產生單例多例:在通用的SSH中,單例在spring中是默認的,如果要產生多例

Java基礎---模式 觀察者模式 反射 工廠模式

package cn.itcast.single; /*  單例設計模式:     懶漢單例設計模式(執行緒安全問題 的解決方案):   步驟:   1. 私有化建構函式。   2. 宣告

模式最好的實現方式靜態內部類的方式

單例模式的優點: 1.在記憶體中只有一個物件,節約記憶體 2.避免頻繁的建立和銷燬物件,可以提高效能 3.避免對共享資源的多重佔用 4.可以全域性訪問 適用場景: 1.需要頻繁例項化然後銷燬的物件 2.

spring模式中執行緒安全問題

@RequestMapping(value = "getPsdbData", method = RequestMethod.POST) public Map<String, Object> getPsdbData(String key,HttpServletRequest reques

Java三大特性:封裝繼承與

(尊重勞動成果,轉載請註明出處:https://blog.csdn.net/qq_25827845/article/details/84592274冷血之心的部落格)           面向物件的語言有三大特性,即封裝繼承與多型。三大特

Java內容梳理(7)封裝繼承和

封裝 (1)封 訪問控制符和內部類均能體現封,起到保護作用。 訪問控制符: public:公開,任何地方均可訪問 protected:受保護的,本類,本包,子類可以訪問 預設(只能在本包,本類下才能訪問) private:私有的,本類才能訪問 (2)裝 方法

Java FP: 偽造閉包工廠建立域物件

原文連結 作者:  Mark Needham   譯者: 李璟([email protected]) 最近我們想構建一個需要使用外部依賴進行計算的域物件,同時我們希望在測試的時候能夠忽略這些依賴。 最開始,我們簡單地在域物件中建立依賴,這使得在測試的過程中,不能隨意修改依賴的值。

-__new____init__

單例 目標 單例設計模式 __new__ 方法 Python 中的單例 01. 單例設計模式 設計模式 設計模式 是 前人工作的總結和提煉,通常,被人們廣泛流傳的設計模式都是針對 某一特定問題&n

SoundPool工具類(模式)相容低版本

public class ClickSoundUtil { private Context context; private static SoundPool soundPool; private static int soundID; public stat

C#/.NET 模式——懶漢式餓漢式三種實現方法

C# 單例模式 ——懶漢式,餓漢式# 註釋: /// 單例模式 /// /// 餓漢式 :第一時間建立例項,類載入就馬上建立 /// 懶漢式 :需要才建立例項,延遲載入 /// /// 單例模式會長期持有一個物件,不會釋放 /// 普通例項使用完後釋放 /// /// 單例

Java面向物件概述及三大特徵(封裝繼承和

一、面向物件思想 Java是面向物件的高階語言,對於Java語言來說,萬事萬物皆物件! 它的基本思想是使用類,物件,繼承,封裝,訊息等基本概念進行程式設計。面向物件程式的最小單元是類,類代表了客觀世界中具有某一特徵的一類事物,封裝了這類事物所具有的屬性和行為。 所以,類定義=成員變數(屬性)+方法(行為