程序員過關斬將--來自於靜態方法和實例方法的聯想翩翩

這兩週沒有妹子來找我問問題,有點小傷感,因此耽誤更新了。哈哈,別當真,由於菜菜這兩週週末都有事(你能夠認爲去公司加班了),實在是沒有精力,忘各位見諒!!java

如下爲菜菜本身觀點,不表明任何妹子的觀點,請輕噴c++

◆◆
面向對象
◆◆

做爲一個久經考驗並獲得業界確定的編程思想莫過於面向對象編程思想了。程序員

面向對象(Object Oriented,OO)是軟件開發方法。面向對象的概念和應用已超越了程序設計和軟件開發,擴展到如數據庫系統、交互式界面、應用結構、應用平臺、分佈式系統、網絡管理結構、CAD技術、人工智能等領域。面向對象是一種對現實世界理解和抽象的方法,是計算機編程技術發展到必定階段後的產物。

談到面向對象思想,首先你得有一個對象才能夠。因此計算機天才在語言角度發揮抽象能力,在編程中把對象抽象建立了出來,典型的表明做就是java/c# 中的類(class)。把每個class的類型看作現實世界中的一類對象,而後根據class 能夠建立出來多個class的實例,把這些實例看作是面向的具體對象。web


爲了完美的支持面向對象,大多數語言都支持了特性:封裝,繼承,多態。這也是諸多蛋疼的面試題中的常見題型。


◆◆
應用場景
◆◆

引入實例化方法概念是面向對象概念出現之後的事情了,區分靜態方法和實例化方法不能單單從性能上去理解,建立c++,java,c#這樣面嚮對象語言的大師引入實例化方法必定不是要解決什麼性能、內存的問題,而是爲了讓開發更加模式化、面向對象化。這樣說的話,靜態方法和實例化方式的區分是爲了解決模式的問題。面試


說的白話一點,究竟是使用實例方法仍是靜態方法取決於業務的場景,當你的業務中每一個對象都有本身的狀態,或者行爲,這些狀態和行爲是隻屬於當前對象的,那你的行爲能夠設計成實例方法。數據庫

舉一個很簡單的例子:一個遊戲的項目中,每一個玩家(player)都有本身的狀態,好比玩家有一個行爲:跳躍,不一樣的玩家跳的距離可能不一樣,因此這個跳躍的行爲體現到代碼上就是一個player類型實例的方法。編程


至於靜態方法,通常的定義成類型的行爲和狀態。由於類型是全部實例共享的,因此一般用做全局共享用途。實際項目中會發現有不少的helper類裏邊都是靜態方法,由於這些方法和具體對象,和具體對象的行爲狀態沒有任何關係。由於和具體實例沒有鏈接,因此這類型的靜態方法幾乎都是線程安全的。c#

舉個很簡單的例子:項目中有不少加密的方法,這些方法的做用就是給一個參數,返回一個結果,沒有任何本身的狀態,因此這些方法被設計成靜態方法。設計模式


在多數項目中,實例方法的使用量要大於靜態方法,爲何呢?由於在多數系統中充斥着各類對象的設計,各類XX設計模式的使用,而這些最終都使用了面向對象的思想。舉一個最簡單的mvc例子,不管是java中仍是c#的 mvc框架,controller中的方法都是實例方法,由於每一個http請求都有本身的狀態,像header頭信息,body信息等,這些狀態是屬於當前http請求的,因此這些controller必須是實例方法才行。緩存


幾乎現代全部的流行編程語言都提供了類型實例的繼承和多態,通通都是爲了更好的服務面向對象這個理念。爲何不提供類型的繼承和多態呢?小夥伴們能夠留言!

◆◆
常見問題
◆◆

靜態方法是類型的方法,實例方法是每一個實例的方法(每一個語言形式不太同樣):

class Bird
    {

        //靜態方法
        static bool IsAnimal()
        
{
            return true;
        }
        //實例方法
        bool IsCanFly()
        
{
            return true;
        }

    }

靜態方法比實例方法快?

菜菜認爲這是錯誤的。一個方法的代碼被加載到內存中,而後被cpu去執行,執行的速度快慢和是否是靜態方法沒有任何關係。可是有一個特殊的場景,那就是GC。實例化太多對象在java/c#這類帶有GC的編程語言中會引起垃圾回收操做,當垃圾回收進行的時候會掛起全部的線程,因此在這個短暫的時間裏,程序會卡頓。

靜態方法常駐內存?

在一個類型第一次被使用的時候,會把靜態方法和靜態變量載入內存,直到進程被銷燬。說道常駐內存,也算是一種誤解,正確的說法是隻有在被使用以後纔會加載進入內存。固然在一些語言中能夠手動卸載當前類型。

靜態方法沒有線程安全問題

菜菜認爲是錯的。有沒有線程安全問題不是是否是靜態所決定的,一個類型也能夠有本身的狀態和行爲,只不過在一個進程中只有一份而已。當一個類型中的狀態被多個線程修改的時候,就會有資源競爭問題,就會有線程安全問題。當一個類型的狀態只有讀的狀況下,能夠認爲讀這個方法是線程安全的。 本身運行一下如下程序的結果

class Program
    {

        static void Main(string[] args)
        
{
            for (int i = 0; i < 20; i++)
            {
                Thread t = new Thread(() => {
                    for (int i2 = 0; i2 < 100000; i2++)
                    {
                        Add();
                    }

                });
                t.Start();
            }
            //爲了模擬程序一直運行
            while (true)
            {
                Console.WriteLine($"Num的值:"+Num);
                Thread.Sleep(1000);
            }

            Console.Read();
        }

        public static int Num;
        public static void Add()
        
{
            Num= Num+1;
        }
    }

至於實例方法的線程安全問題,原理相似。有沒有線程安全問題取決於狀態有沒有被多個線程併發修改,有沒有資源競爭,和是否靜態徹底不要緊。

THE END


程序員修神之路--問世間異步爲什麼物?
程序員修神之路--提升網站的吞吐量🤺
程序員修神之路--🤠分佈式高併發下Actor模型如此優秀🤠
程序員過關斬將--論商品促銷代碼的優雅性
程序員過關斬將--請不要隨便修改基類
程序員過關斬將--你的面向接口編程必定對嗎?
程序員修神之路--高併發下爲何更喜歡進程內緩存
程序員修神之路--高併發優雅的作限流

相關文章
相關標籤/搜索