與 excel 絕對位置的觀念一樣
所有的物件都共用同一屬性
Class 的屬性可分為:
物件類:
每個物件都有自己的屬性內容
透過實體化出來的物件來呼叫物件類的屬性
案例介紹:
本金都固定,比較各家銀行儲蓄方案
class Bank {
int _pv;
double _rate;
int _n;
int _fv;
Bank(this._pv, this._rate, this._n) {
_fv = (_pv * (1 + _rate * _n)).toInt();
}
void setPv(int pv) {
this._pv = pv;
}
void show() {
print("本金 = $_pv, 利率 = $_rate, 期數 = $_n, 單利本利和 = $_fv");
}
}
main() {
/*
Bank m1 = new Bank(100000, 0.01, 6);
物件類屬性:
m1.pv
m1.rate
m1.n
m1.fv
*/
Bank yuantaBank = new Bank(100000, 0.01, 3);
Bank taiwanBank = new Bank(100000, 0.012, 5);
Bank esunBank = new Bank(100000, 0.015, 10);
yuantaBank.show(); //印出 本金 = 100000, 利率 = 0.01, 期數 = 3, 單利本利和 = 103000
taiwanBank.show(); //印出 本金 = 100000, 利率 = 0.012, 期數 = 5, 單利本利和 = 106000
esunBank.show(); //印出 本金 = 100000, 利率 = 0.015, 期數 = 10, 單利本利和 = 114999
/*
若之後想修改本金看看新結果,每一個物件還需要各自修改
例如:
yuantaBank.setPv(200000);
taiwanBank.setPv(200000);
esunBank.setPv(200000);
所有物件都使用同一個屬性內容,故應宣告為類別類屬性
*/
}
類別類:
因為每個物件都呼叫同一個屬性內容,故稱類別類的屬性,不需透過物件,可以直接透過類別呼叫
class Bank {
static int pv; //類別類屬性
double _rate;
int _n;
int _fv;
Bank(this._rate, this._n) {
_fv = (pv * (1 + _rate * _n)).toInt();
}
void show() {
print("本金 = $pv, 利率 = $_rate, 期數 = $_n, 單利本利和 = $_fv");
}
}
main() {
//呼叫類別類,直接對 類別類的屬性做傅值
Bank.pv = 100000;
Bank yuantaBank = new Bank(0.01, 3);
Bank taiwanBank = new Bank(0.012, 5);
Bank esunBank = new Bank(0.015, 10);
yuantaBank.show(); //印出 本金 = 100000, 利率 = 0.01, 期數 = 3, 單利本利和 = 103000
taiwanBank.show(); //印出 本金 = 100000, 利率 = 0.012, 期數 = 5, 單利本利和 = 106000
esunBank.show(); //印出 本金 = 100000, 利率 = 0.015, 期數 = 10, 單利本利和 = 114999
/*
若之後想修改本金看看新結果,直接對類別類共同屬性pv 做修改即可
例如:
Bank.pv = 200000;
*/
}
使用對象:
field區屬性,即靜態變數,又稱類別類變數
常用在對類別的共用狀態屬性以及常數上,在使用之前不會初始化
class Queue {
static const initialCapacity = 16;
// ···
}
void main() {
print(Queue.initialCapacity); //印出 16
}
方法(函數),即靜態方法(函數),又稱類別類方法
靜態方法不在instance 例項是執行,所以無法使用this
(物件本身的變數,即class的field區)
import 'dart:math';
class Point {
num x, y;
Point(this.x, this.y);
static num distanceBetween(Point a, Point b) {
var dx = a.x - b.x;
var dy = a.y - b.y;
return sqrt(dx * dx + dy * dy);
}
}
void main() {
var a = Point(2, 2);
var b = Point(4, 4);
var distance = Point.distanceBetween(a, b);
print(distance); //印出 2.8284271247461903
}
補充:
類別的 Constant constructors(常量建構式)
如果要設計一個類別讓它生成的物件狀態永遠不會改變,可以把這些物件定義為編譯時常量,要實現這個功能,則需要定義一個const
建構式, 並且宣告所有類的屬性皆為final
class ImmutablePoint {
static final ImmutablePoint origin =
const ImmutablePoint(0, 0);
final double x, y;
const ImmutablePoint(this.x, this.y);
}
void main() {
ImmutablePoint a = ImmutablePoint(3,4);
// a.x = 5; 會報錯,ImmutablePoint 生出來的物件a,它的變數為常數,不能改變
print("x = ${a.x}, y = ${a.y}"); //印出 x = 3, y = 4
}
類別的 Factory constructors(工廠方法建構式)
當建構式不需要每次都創建新的實例時,可以使用factory
來定義這個建構函式。例如,一個工廠建構函式可能從快取中獲取一個例項並返回,或者返回一個子類別的例項 (子類別後面會再介紹)
Factory constructors 一樣不能使用
this
class Logger {
final String name;
bool mute = false;
static final Map<String, Logger> _cache = <String, Logger>{};
factory Logger(String name) {
if (_cache.containsKey(name)) {
return _cache[name];
} else {
final logger = Logger._internal(name);
_cache[name] = logger;
return logger;
}
}
Logger._internal(this.name);
void log(String msg) {
if (!mute) print(msg);
}
}
void main() {
var logger = new Logger('UI');
logger.log('Button clicked'); //印出 Button clicked
}
程式碼中可以有異常和捕獲異常,Exceptions 表示在執行程式期間出現的問題,發生一些未知的錯誤情況,若沒對這些Exceptions 作處理,會導致我們程式結束執行。和java 不同的是,所有的Dart 異常是非檢查異常 unchecked exceptions,方法不會聲明它們可能引發的異常,並且不需要捕獲任何異常。
Dart提供了Exception
和Error
型別,以及一些子型別。還可以自己定義異常型別。但是,Dart程式碼可以丟擲任何非null物件為異常,不僅限於Exception
和Error
物件。 ( 不過還是建議使用Exception
和Error
型別 )
拋出異常:
throw new FormatException('Expected at least 1 section');
還可以拋出任意物件:
throw 'Out of llamas!';
捕獲異常:
將可能發生錯誤的程式碼放在 try
區塊內,用on
/catch
處理發生異常時要做的動作
main() {
try {
testAge(-2);
} catch (e) {
print('Age cannot be negative');
}
}
void testAge(int age) {
if (age < 0) {
throw new FormatException();
}
}
要處理可能拋出多種型態異常的程式碼,可以指定多個catch
語句。每個語句分別對應一個異常型別,如果catch 語句沒有指定異常型別,則該語句可以處理任何異常型別:
try {
breedMoreLlamas();
} on OutOfLlamasException {
// A specific exception
buyMoreLlamas();
} on Exception catch (e) {
// Anything else that is an exception
print('Unknown exception: $e');
} catch (e) {
// No specified type, handles all
print('Something really unknown: $e');
}
如上述程式碼所示,可以使用on
或者catch
來宣告捕獲語句,或兩者同時使用。使用on
來指定異常型別,使用catch
來捕獲異常物件。
函式catch()
可以帶有一個或者兩個引數,第一個引數為丟擲的異常物件,第二個為 StackTrace object。
try {
// ···
} on Exception catch (e) {
print('Exception details:\n $e');
} catch (e, s) {
print('Exception details:\n $e');
print('Stack trace:\n $s');
}
要部分處理異常,同時允許異常傳遞,可以使用rethrow
void misbehave() {
try {
dynamic foo = true;
print(foo++); // Runtime error
} catch (e) {
print('misbehave() partially handled ${e.runtimeType}.');
rethrow; // Allow callers to see the exception.
}
}
void main() {
try {
misbehave();
} catch (e) {
print('main() finished handling ${e.runtimeType}.');
}
}
無論是否拋出異常,都要確保某些程式碼會執行,可以使用finally
語句來實現。如果沒有匹配的catch
語句來捕獲異常,則該異常會在執行finally
語句後被拋出
try {
breedMoreLlamas();
} finally {
// Always clean up, even if an exception is thrown.
cleanLlamaStalls();
}
定義的finally
語句在任何匹配的catch
語句之後執行:
try {
breedMoreLlamas();
} catch(e) {
print('Error: $e'); // 先處理異常
} finally {
cleanLlamaStalls(); // 再執行 finally語句
}
現在我們對於使用一個類別的操作上有比較熟悉了,包括如何設計類別、使用它的變數以及方法等等,接下來我們將介紹,類別的繼承、多型的內容,Dart 的語言介紹系列還會有幾天,為了讓以後我們能夠更順利開發專案,這幾天可能會辛苦一點