metal35x

@metal35x

Joined on Nov 25, 2019

  •  Like 68 Bookmark
  • 物件導向的三大特性:封裝、繼承、多型 A.封裝性(Encapsulation): 封裝(Encapsulation)的概念就是在程式碼中設置權限,讓不同的物件之間有不同的存取限制,而不是把所有資料都攤在陽光下讓大家使用。「封裝」可防止程式的原始碼被竄改,保障了資料的隱密性,並提高了程式的穩定性和安全性,你總不可能希望辛苦做好發佈出去的程式,可以被使用者隨便亂改吧? 封裝的程式碼實作是透過「存/取控制修飾子」來達成的,不同的程式語言會有更細緻的分類與不同的使用方法,但我們這裡只介紹最常用的三種:public、private和protected。 封裝性的「存/取控制修飾子」: 「存/取」是兩個動作,也就是儲存和取用,但我們一般把它當作「使用」的意思就好,並直接合併在一起稱呼它為「存取」。
     Like 30 Bookmark
  • 函數中資料的傳遞:傳值、傳址、傳參考 以下的說明是每種程式語言都通用的觀念,但不同程式語言有不同的語法,以及不同的程式語言不一定都支援全部的傳遞方式,要看你使用的是哪種程式語言。 把資料輸入到函數中進行運算,在程式語言中有個專業的術語叫做「傳遞」(pass)。例如函數Y(x) = 3x + 1,若我們設定x = 2,則把x = 2丟進去Y(x)函數中做運算,術語就稱為傳遞,而Y(x)函數輸出的結果是7,數學式寫作Y(2) = 7,應該很容易理解。 另外,關於函數的「引數」與「參數」,這兩個重要觀念很多人說不清楚,可能連程式經驗豐富的人都還是對它們的區別一知半解。但這是很重要的觀念,必須要徹底理解,我有信心這篇文章應該是你看過最清楚的解說了。 所以,在解說函數傳遞的三種方式之前,先釐清一下何謂函數的引數和參數。 函數的引數(argument) v.s. 函數的參數(parameter) 在使用函數(或稱函式或副程式)時,往往會遇到這兩個名詞,時常造成混淆,每人翻譯的也不盡相同,但由於非常重要,必須做好釐清。
     Like 17 Bookmark
  • 物件導向程式設計(Object-Oriented Programming,縮寫為OOP) 「物件導向」是我們每天身在其中已經太過熟悉,以至於平常根本不會把它拿出來特別討論的事情。我們日常生活無時無刻都是物件導向,就像呼吸一樣自然而然,例子多不勝數。例如,我現在坐在電腦前面一邊打字一邊聽音樂,用物件導向的方式來表達的話,就像下面這個樣子: 「我」是個物件、電腦、鍵盤、滑鼠、螢幕、喇叭 … 也都是物件,這個例子就是「我」這個物件和其他物件彼此之間進行互動的過程。 而「人類」是個類別(class),因為地球上的人口有七十幾億,如果不清楚定義出到底是哪一個人在打字,要怎麼開始互動?同理,電腦、滑鼠、鍵盤、螢幕、喇叭 … 也都只是類別(class),還要再指出它的具體名稱,才知道你到底用的是地球上超多台電腦的哪一台,使用的是哪一個鍵盤、滑鼠、螢幕…。之後,把每個物件的屬性和使用方法詳細定義出來,就可以把這些物件集合起來,以物件彼此之間的(使用)方法(method)來做互動了,這就是物件導向的核心觀念。 而現在我們做的事情是使用電腦打字和聽音樂,所以我穿什麼顏色的衣服、聽的是哪一首歌、桌上放的是什麼飲料 … 這些資訊對目前要做的事情都沒有意義,可以不用描述,只要把有意義的東西彙整起來就好了。
     Like 16 Bookmark
  • 我們先說何謂MCU,它是Micro Controller Unit的縮寫,中文翻譯為「微控制器」,但其實它就是一顆CPU(Central Processing Unit),所以我比較喜歡叫它「微處理器」。顧名思義,它就是我們個人電腦(PC,Personal Computer)裡面CPU的微型化版本,我們個人電腦裡面的CPU已經夠小了,不過它還能再縮小,小到能夠塞進一顆IC裡面。如下圖,在IC封裝內部中間那個超小的chip就是MCU的本體,其他都是散熱構造和金屬接點,而整個IC封裝的尺寸就和小拇指差不多。 MCU本質上它就是CPU,它執行的就是各種數學和邏輯運算,和我們個人電腦的CPU功能類似,只是效能弱很多,但如果不玩3D遊戲,一些較為簡單的應用場合已經足夠應付了。而如果把MCU安裝到一塊電路板上,並搭配上記憶體模組、電源I/O模組,以及各種訊號的輸入和輸出接腳,便成了一個比手掌還小的電腦,具備有電腦的一切特質和功能,只是不一定有安裝作業系統(Operation System)。  註:請參考:馮紐曼提出的電腦(或稱計算機,Computer)的五大(硬體)架構。 使用效能比較陽春的MCU,而且沒有安裝作業系統、沒有硬碟,手掌大小的電腦,最著名的產品就是Arduino,俗稱Arduino開發板。 而使用效能比較強、體積比較大一點的MCU,並配上Linux作業系統和更完整的I/O(Input和Output),可以連接和PC一樣的液晶螢幕,還可以使用SD記憶卡充當硬碟,使它更像一台個人電腦,最著名的產品就是樹莓派(Raspberry Pi),所以也有人稱樹莓派為單版電腦。
     Like 38 Bookmark
  • 建構子(constructor) 建構子的英文為constructor,中文沒有統一的翻譯,通常稱為「建構子」、「建構式」、「建構元」或「建構函數」、「建構函式」…,都是在說同一個東西。 我們知道一個類別(class)內部定義了成員變數(JAVA的術語稱為成員屬性,或簡稱屬性(attribute))和成員函數(JAVA的術語稱為成員方法,或簡稱方法(method))。也就是說,類別定義了一些具體的屬性和方法,一旦類別做了實體化的動作之後(new關鍵字),就可以產生物件,這個(具體的)物件就會擁有該類別所定義的屬性、並且可以執行該類別所定義的方法。  註:此處先不討論靜態static的情況。 我們以實際的程式碼來說明,先定義一個類別:
     Like 9 Bookmark
  • 前瞻知識: 方法 method: class Power :// 此稱為一個類別 def computer (): // 此稱為一個方法 ... def phone () // 這也叫一個方法 ... 功能 function: def computer: // 此稱為一個功能 function ...
     Like 41 Bookmark
  • 結構體(struct) 「struct」是個C語言的關鍵字(keyword,又稱保留字),為英文structure的縮寫,中文翻譯作「結構體」,簡稱「結構」,是一種「使用者自訂」的「資料型態i」,並且它是物件導向語言中「類別」(class)的前身。 C語言已經有內建short、long、int、float、double、char … 等「資料型態」,不過由於這些資料型態的變數彼此之間可能會有某種相關性,例如班級中每個學生的成績單上都會有:1.學號(字元陣列或字串型態),2.數學成績(整數型態)3.英文成績(整數型態)4.平均成績(浮點數型態),所以我們就可以說成績單就是一種結構(struct)的資料型態,因為成績單整合(綁定)了字串(在C語言是字元陣列)、整數和浮點數這三種資料型態的變數。 如同成績單的例子,結構(struct)是一種我們自訂的「資料型態」,可以更清楚地表現出變數之間的關聯性,方便我們管理與使用資料。換句話說,struct就像int、float、double、char … 一樣是種「資料型態」,只不過int、float、double、char … 是C語言內建的資料型態,而struct xxx的「xxx」是我們「自訂」的資料型態。 重點是,我們並不是自己創造一個很厲害的資料型態,例如什麼超級整數、快速浮點數、閃電字元…等,這些都是我亂掰的,我們只是「綁定」int、float、double、char … 這些基本的資料型態,成為我們自訂的資料型態。如下圖,我們使用關鍵字struct告訴C語言編譯器,我們現在開始要來做一種自訂的資料型態,我把它命名為「TestScore」來代表成績單使用的資料型態(可任意取名,但名稱要有意義才方便使用),TestScore這種資料型態綁定了char、int、float這三種資料型態(的變數),術語稱為:「TestScore是一種結構化的資料型態(data type)」。  註:習慣上(約定俗成),對於自訂的資料型態名稱,開頭首個字母會使用大寫以示區別,例如這裡的TestScore。它也融合了駝峰式命名法,和「Test_score」是同樣意思。
     Like 5 Bookmark
  • 訊號依據它的特性,分成類比訊號(analog signal)與數位(digital signal)兩種。 大自然產生的訊號絕大多數都是類比(analog)訊號,例如光線的明暗、聲音、力量、溫度、濕度…等,都是連續且平滑的訊號。例如光線,有完全不亮、一點點亮、有點亮、超級亮 … 等程度上的區別,而且它是連續且平滑過度的,並不是只有亮和暗兩種狀態。至於其他的類比訊號,例如溫度、溼度 … 也都很容易理解。 數位(digital)訊號通常是人為產生的,最簡單的例子就是電燈的開與關,除非是可調式的電燈,最簡單的電燈一般只有開(亮)和暗(不亮)兩種狀態。但我們講數位訊號,應用最多的還是在電子電路中,例如電腦(計算機)和各式各樣的電子產品,都只能處理數位訊號。 數位的世界只有0與1,也就是高電壓與低電壓兩種狀態,當然不是連續的訊號,那我們要怎麼輸出自然界常見的的類比訊號呢?科學家們想說,那就用數位訊號去「模擬」類比訊號吧!這就是PWM的基本觀念。 數位to類比轉換器(Analog-to-Digital Converter,簡稱ADC)
     Like 1 Bookmark
  • 當我們已經學會了程式語言的基本觀念,接下來最重要的就是如何活用我們學過的東西,實際做出一個有用的程式,也就是設計並撰寫演算法。 由於計算機(computer、台灣俗稱電腦)的運作是非常簡單而原始的,對已經習慣高階和抽象化思考的人類來說,一開始無法立刻轉換思維去適應機器「這麼笨」的運作方式,當然會覺得困難。但只要經過適當的訓練,將腦袋調整一下,轉換立場站在計算機的角度來思考,就會比較容易寫出演算法。 第一步,我們要先知道自己到底想要做出什麼樣的程式,它是怎麼被使用的,以及會產生什麼樣的結果。之後,我們就要練習把每個具體細節都拆分出來,不斷的拆分、分解成一個個具體可行的數理和邏輯步驟,最終像拼圖一樣把它完整的拼出來,成為一個完整的程式。 對於初學者來說,即使變數、陣列、迴圈、條件判斷…甚至指標的觀念都知道,但要把這些知識串聯起來,實際撰寫一個演算法可能還是有點困難,不知從何下手。也就是說,雖然手邊的材料已經非常齊全了,但初學者還是不知道著手利用這些材料做出一盤好菜。 一般來說這沒有捷徑,只能透過不斷的嘗試錯誤、不斷練習,在跌跌撞撞中學習成長,最後變成高手。話雖這麼說,其實設計一個演算法還是有訣竅的,知道這些訣竅可以減輕新手在學習與成長過程中的痛苦,更快進入適應期。
     Like 4 Bookmark
  • 如果一個類別的{ }之內又定義了其他類別,就稱為(該類別的)內部類別(inner class),而把最外層的類別稱為外部類別(outer class)。  註:若沒有定義內部類別,自然也就沒有區分內、外了,就是我們最常使用的普通類別。 以一個汽車引擎來說,一般人都會把引擎當作是一個物件整體,當故障時我們只會說是引擎故障,請專業人員來維修。不過在專業技師的眼裡,引擎內部還有非常多的內部類別,他明白引擎系統之內還有很多系統,例如電噴系統(或化油器)、火星塞系統、活塞系統、阻風門系統 … 甚至是ECU系統,只要其中一個系統故障,對外呈現出來就是車主說的「引擎故障」。 以這個例子來說,你可以把引擎內部所有的系統都寫成引擎類別的內部類別,也可以不使用內部類別,像我們一般常規的方式,把每個系統都寫成各自的(外部)類別,再組裝成一個引擎整體。 內部類別的程式碼看起來像這樣: class Outer{
     Like 5 Bookmark
  • this關鍵字: this在英文的意思是「這個、這裡」,不過在程式語言中,要把它記為「這個類別的…」或「這個物件的…」。打個比喻,你要送包裹給大樓的王先生,但如果同一棟大樓裡有很多個王先生,你就必須和大樓管理員說明:「是五樓之三的那個王先生」才能順利把貨送到他手上。 意思就是,程式雖然不容許變數在同一個{ }區塊之內「撞名」(即變數的名稱完全相同),但如果同名的變數位於不同的{ }區塊,程式仍可區分出來,語法上仍是合理的,這就是區域變數(local variable)和全域變數(global variable)的觀念。不過,程式有條預設規則:「當敘述所在之處有相同名稱的全域變數和區域變數時,則該敘述優先使用區域變數」,這就會造成我們無法順利的將資料傳遞到我們想要的地方。  註:回顧個基本觀念,絕大部分的程式語言都會區分大小寫,故apple和Apple是不同的名稱。 來做個示範,以下故意讓類別的屬性(成員變數)和建構子的引數撞名:
     Like 4 Bookmark
  • 指標(pointer): 「指標」可說是C或C++的大魔王了,指標易學難精,但由於很少有書或資料能夠把指標做清楚的解釋,可能連上課的老師都說不清楚(還是用術語解釋術語),造成多數初學者根本鴨子聽雷,光是連指標是什麼都搞不清楚,就失去學習興趣了。 指標(pointer)是源自於早期電腦科學和程式語言發展的一個必然過程。其實任何程式語言都一定會有指標的觀念和操作,只是後來比較新的程式語言考慮到指標的易學難精,使用難度高,而且有一些副作用,和自己主打簡單易用的理念不合,因此很多比較新的程式語言,都把指標巧妙的包裝成另外的形式,不讓使用者直接使用「 * 」和「&」運算子來操作指標。例如Java就把指標的觀念給巧妙的包裝成為「參考型態」,讓使用者能以更單純的方式操作指標,而不必被「 * 」和「&」運算子搞得頭昏腦脹。 所以反而指標變成C語言(主要發展期:1969年到1973年)最大的招牌特色了,就像市面上的車子已經都改為自動排檔,而還有手動排檔的老車,反而變成了它的特色。 指標用的好,對於熟練的人來說,指標提供了最大的靈活度,讓設計者能對記憶體的使用方式做很好的手動控制,就像開手動排檔的賽車手;而不使用指標,就像開自動排檔的一般人,雖然一樣能到達目的地,但有些過程就無法達到最佳化,要實現某些操作也不那麼方便。 不過,因為指標能夠直接操作電腦的底層硬體,能夠手動控制電腦使用記憶體的方式,因此指標是一把雙面刃。雖然對電腦來說都沒差,但對人類來說,只要觀念不清楚,一旦指標操作錯誤就會造成系統崩潰,或者影響程式的穩定性。而使用指標,對不那麼熟練的人來說,也造成無謂的複雜度,讓程式變得艱澀難懂,不只容易寫錯產生bug,也難以除錯(debug)。
     Like 6 Bookmark
  • PID是「Proportional–Integral–Derivative」的縮寫,是一種「自動控制」的方法,非常廣泛的應用在各個領域中,以達到精確的控制。 我們以機器手臂來做例子,當我們設定了一個終點座標,讓機器手臂移動過去,假如不使用PID控制,雖然機器忠實的執行在終點座標停下的指令,但會因為前進的慣性,機器手臂仍會在超過終點後的位置才停下來,無法很精確的剛好停在終點那個位置上。更糟糕的是,當機器手臂上的距離感測器(sensor)感測到衝過頭了,於是把訊息反饋(feedback)給MCU,MCU便命令手臂往回折返,但折返時卻仍然一樣會衝過頭,於是就變成像鐘擺一樣,在終點附近不斷晃動搖擺,當然這不是我們要的。 若需要比較精確的控制,則要使用PID控制方法。如上例所說,PID的P代表比例、I代表積分、D代表微分。若採用PID控制,則在一開始機器手臂的位置離終點座標還很遠的時候,PID的比例演算法(P)此時會占有比較大的權重。經過比例計算(P)後,由於目前距離較遠,P值還很大,MCU會讓機器手臂以比較快的速度往終點移動,並在快到終點時讓它逐漸慢下來。 而在目前座標與終點座標的差值更加縮小時,積分(PID的I)的計算便逐漸取得更大的權重。這個積分是計算一段時間內與終點座標誤差的總和,愈加接近終點,積分值自然會愈小,機器便可依據這個值來修正移動的速度。 最後,當距離差值更加縮小時,會計算期望值與實際值之間的變化率(PID的D,即微分),當變化率小於某個程度之後(看寫程式的人怎麼設定),MCU便認為機器手臂到達終點了,讓控制手臂移動的馬達完全停止轉動,機器手臂便可以很平順的剛好停在終點。
     Like 6 Bookmark
  • final是一個修飾子,專門用來「鎖定」被它修飾的東西,它可以使用在以下三種狀況下: 修飾一個變數和函數內的參數,讓這個變數或參數變成「常數」(constant),使得它的值無法再被取代、更改。 修飾一個方法(method),讓這個方法不能被其子類別給覆寫(override)掉。 修飾一個類別(class),讓這個類別無法建立其子類別,就是把這個類別給「絕育」的意思,術語為「終止繼承」。 以下先講解第1.點,也就是「常數」的應用。 我們知道「變數」(variable)裡面存放的是「變動值」,可以隨時以新值取代舊值。 而常數(constant)裡面存放的是固定值,不可以用新值取代舊值。若不希望之後此值被變動到,可以將之宣告為常數。宣告時在最前方加入「final」關鍵字,會宣告為常數,賦值一次後,不能再修改變更,否則會報錯,也就是說final型態不能重覆賦值。
     Like 3 Bookmark
  • 「抽象化」的概念非常簡單,對於一件事物,它的運作原理可能十分複雜,例如一台汽車,但我們駕駛人在開車的時候不需要去管引擎的運作原理、車內冷卻水的循環、輪胎差速器的運作 … 我們只要把精力放在油門、剎車和方向盤的控制就好了。這種只關注一個事物的某些部份,而把其他部分當作一個整體,或者說是「黑盒子」的作法,就是抽象化。 數學或程式的函數(function)就是抽象化的典型例子。例如,我們只要知道一個函數需要餵給它什麼input,然後它就會吐出什麼output就可以了,即使根本不知道這個函數的演算法到底是怎麼寫的,我們還是可以拿它來完成工作。 也就是說,我們不必是開發這個函數或演算法的專業科學家或工程師,透過「抽象化」的觀念,我們只要知道怎麼去使用它就可以了。而如果我們想要去深究這個函數的詳細內容,只要開發者允許並授權給我們,就可以了。或者,我們也可以自己開發函數,抽象化(撰寫函數的使用說明,例如告知別人如何給input,以及會得到什麼output)之後發布給別人使用。 尤其在科學領域,知識是大量堆疊累積起來的,要求一個人「究天人之際,通古今之變」是不切實際的,所以科學家們大量運用抽象的精神,在很多時候只關注一個複雜模型或理論的某些特性和應用方式,而不去管它的詳細內容。當我們想要了解詳細的內容時,再去把這個「黑盒子」拆開詳細研究就可以了,這樣可以幫助我們把精力聚焦,放在不同時間、不同場合真正應該關注的事情上。 所以也有人把abstraction翻譯為「萃取」、「摘要」或是「歸納」,意思是將某個事物的重點萃取或歸納出來,只關注我們在這時候需要關注的部分。例如我們只是使用者,就可以不用去管機器的運作原理,只要會使用就好了;但如果我們是開發者,就要把精力放在機器的內部結構、製造成本,以及如何讓機器運作得更快更好,更方便使用上。
     Like 2 Bookmark
  • 在Java中,static關鍵字可用來修飾屬性、方法和類別。 在屬性、方法或類別前面加上關鍵字「static」,就是告訴Java編譯器,遇到static修飾的東西,就要優先分配記憶體空間給它。 要更深入了解static的意義,要搭配「全域變數和局部變數」的觀念一起看。static修飾的東西就相當於全域變數,在程式的進入點main()方法「之前」就會被分配到記憶體空間,並且不會在執行完一段敘述之後就釋放出記憶體空間,除非程式結束,都會保留著static的資料,所以也有「共享」的功能。 比較有加static跟沒有加static修飾的差異,決定性的不同是「載入記憶體的時機」。static關鍵字修飾的東西,在程式的進入點main()方法「之前」就會被分配到記憶體,並且在整個程式的執行期間都不會釋放掉static資料的記憶體空間,所以才稱為靜態。 可以被宣告成靜態(前面加上static關鍵字)的東西有屬性、方法和類別。不過只建議使用靜態類別,原因以下詳述: 一、靜態屬性(static property): 我們可以不要用static修飾一整個類別,而可以只修飾類別中的某一個屬性(成員變數)。存取的方式是: 類別名稱 . 靜態屬性 ; 就像我們存取一般物件的屬性一樣,是透過「.」運算子來存取,但靜態屬性要使用類別名稱去存取,而不是物件名稱。
     Like 2 Bookmark
  • getter()或setter()方法 getter()和setter()方法是種名詞上的泛稱,用比喻的來說,就是指一個類別(或物件)之中,private屬性(成員變數)的管家。 由於private屬性非常自閉,完全不與同一類別(或物件)以外的任何事物互動,因此只好委託這兩個和它在同一類別(或物件)之內的管家代勞,協助管理private屬性與外界的「溝通」。而這兩個管家,getter()負責將private的資料傳出到外部,也就是外部的物件可以透過getter()這位管家得到private屬性的資料,相當於送件員;而setter()正好相反,它負責接收外部的資料,並將處理過後的資料傳遞給private變數,相當於審查者。 而無論是getter()或是setter(),其實也就是一般的public方法(成員函數),所以我們可以為它們定義實作的程式碼,告訴它們要如何運算、處理資料,之後才去存 / 取private屬性。也就是說,這個送件員或審查員,可以經過把資料改寫、處理的動作後,才去存 / 取private屬性,保護它不被隨意亂動,但又達到可以使用它的目的,也就是說getter()或setter()是作為private屬性輸入 / 輸出的控制方法。 想當然爾,這兩個管家(getter & setter)一定要是public的,這樣它們才有辦法與外界互動,不能連管家都搞自閉。
     Like 6 Bookmark
  • 程式的架構與進入點: 要了解程式的結構,首先要知道程式的進入點,也就是「main()方法」(也可以稱作main()函數)。main()方法,和C語言與其它的程式語言一樣,它是Java程式的「進入點」(Entry point),也就是說,程式的執行順序是由「進入點」開始的。可以把main()方法比喻成「劇院的入口」,一旦執行程式,Java就會優先找到main()方法,從該行開始執行程式,而不是程式的第一行喔。 在Java中作為進入點的main()函數,語法如下: class Test{ public static void main(String[ ] args){ System.out.println("Hello Java~~"); } }
     Like 6 Bookmark
  • Java的方法鏈(method chain) 方法鏈(method chain)顧名思義,就是把一些方法串接起來,讓前一個方法回傳「處理過後的物件」,並且讓它再去執行下一個方法。 舉個例子,假設我們宣告一個「廚師」類別,並且將它實體化,建立一個叫做「小當家」的具體物件,小當家可以使用「收集食材()、加水()、大火快炒()、加米酒()、瀝乾()、加上蔥花()」這些方法來做菜,但如果我們這樣寫: 小當家 . 收集食材(); 小當家 . 加水(); 小當家 . 大火快炒(); 小當家 . 加米酒();
     Like 4 Bookmark