1.4 Develop code that declares both static and non-static methods, and - if appropriate - use method names that adhere to the JavaBeans naming standards. Also develop code that declares and uses a variable-length argument list.
method和non-local variable統稱為members
可以使用non-access modifier(strictfp, final, abstract)修飾members
存取修飾子
- Class只能使用public or private (原因:protected是同package class+subclass能夠存取,但什麼情況下一個A package的class能夠extends B package的class,但 B package class又只限B package內的class存取使用?因此一般來說定義protected沒有必要,就和定義default class一樣。)- members可使用四種access control等級
- access control有兩個議題:
- class內的method是否可以access另一個class member(dot operator)
- subclass是否可以extends parent-class的member(subclass宣告了擁有superclass的所有member)
- 假如A class不能夠被B class存取,代表A的所有member不能被B class存取(即使A member有設定為public的variable or class)
- this 這個參考一定是指到此刻正在執行的object
Ex:
Bicycle.java
applyBreak() { }
makeStop() {
applyBreak();//同class呼叫method
|}
MountainBike.java extends Bicycle.java
doThings() {
Bicycle bk = new Bicycle();
bk.applyBreak();//透過class的reference呼叫method
}
doMore() {
applyBreak();//繼承的method (沒有dot等於暗中使用this.applyBreak())
}
Driver.java
doDriverStuff() {
Bicycle car = new Bicycle();
car.applyBreak();//透過class的reference呼叫method
MountainBike mb = new MountainBike();
mb.applyBreak();//透過class的reference呼叫method
}
私有成員(Private Members)
- 假如一個subclass嘗試繼承supercalass的 private class將會有錯誤訊息跳出
- subclass可以重新定義superclass的method(這不是override),只是一個名稱恰好相同的method
- 雖然可以將instance variable標示為public,但實務上盡量將variable保持private or protected。developer應該透過setter methods(設值函數) and getter methods(取值函數)操作變數。如此可以透過method檢查設定的值是否有問題。
保護(Protected)和預設(Default)成員
- protected和default兩者的members都能夠被同一個package的class存取,最大的差別在於,protected的members能夠被subclass存取(使用繼承方法,而非建立實體使用dot存取),即使在不同的package內
- 若package外的subclass使用superclass的reference access members,protected 等級就會像default等級一樣,無法使用。
- protected會顧及到父子關係
- protected (pacakge+child)
- default (package)
package A;
public class Parent {
protected int x = 1;
}
package B;
import A.Parent;
class Child extends Parent {
public void test() {
System.out.println("x is " + x); // 因為是subclass,且x為protected,在不同的package還是可以繼承
Parent p = new Parent();
System.out.println("x is " + p.x); //錯誤,因為對p來說已經是不同package之間去存取protected的變數
}
}
package B;
class Other {
public void test() {
Child cd = new Child();
System.out.println("child x is " + cd.x);//錯誤,這個x對於其他package的class而言已經變成private了
}
}
Local Variables 和 Access Modifiers
- access modifier不可應用在local variables上。
- 只有final可以用在local variables上
非存取的成員修飾子
Final Method- 避免修改
- 防止method被副寫也消滅OO優勢
Final Arguments
public Human getAge(int birth, final int growIndex) {}
- method arguments規則與local variables一樣,能夠使用final modifier/
- 上述例子表growIndex不能在method內被修改
Abstract Methods
- 一個abstract method需要以分號作為結尾,意即沒有method body
Ex1:
public class Human {//錯誤,沒有宣告abstract的class內不應該有abstract method
public abstract void attack();
}
Ex2:
public abstract class Human {//正確,abstract class可以沒有包含abstract method
void heal() {...}//
}
以下三個原因表示heal()不是一個abstract method
- heal()沒有abstract
- heal()有大括號
- heal()有提供實作程式碼
- 任何extends abstract class的subclass都必須要implement所有superclass的abstract class,除非subclass也是abstract的
- 第一個concrete subclass必須要implement所有superclass(所有inheritance tree)的abstract class
- abstract目的是:superclass不知道subclass在此method需要有怎樣的行為; final目的是:superclass知道關於所有subclass在此method需要有如何的行為(因此abstract和final為對立的)
- private不能被subclass看到,無法繼承,因此也不能與abstract共用
- abstract無法和static一起共用
Synchronized method
- 意指該method一次只能被一個thread存取
- Synchronized可以加上final
public synchronized void increment() {c++;}
Native 函式
- native只能應用在mehod上,不能用在class, variable上
- native的宣告必須以分號作為結尾(就像abstract method一樣)
public native int intMethod(int i);
Strictfp 函式
- 目的 : 強迫floating point遵循IEEE754標準,不論在哪個平台運行都可以預測floating point的行為;缺點是當底層平台支援更精準的運算,strictfp將無法使用此優點
- strictfp可以用來修飾class及method
- strictfp不能用來當作變數的宣告
Variable Argument Lists(簡稱var-args) method
- 以下皆為var-args
- variable-length argument lists
- variable arguments
- var-args
- varargs
- variable arity parameter
- 定義argument及parameters
- argument:call method時,放在括號內的東西 ex: name.doMethod("someString", 25);
- parameter: method's signature. ex: public void doMethod(String s, int i) { .. }
- var-args宣告規則
- type: 一個var-arg parameter並須指定可以接收的argument type。可以是primitive type(基本型別),也可以是object type
- 語法: type + (...)省略符號 + 空白 + 接收parameter的array名稱
- 帶的parameter可以是0到n個
- 其他參數: 使用var-arg的method可以同時擁有其他的parameter
- 限制: var-arg必須是method signature上的最後一個parameter,而且一個函式只能有一個var-arg
- 一般來說overloading的var-args method會是最後一個選擇
void average( double... numbers ){ }
void average( char c, double... numbers ){ } //可以有其他parameter
void average( Ant... ant){ } //使用object Ant type
非法的:
void average( double numbers...){ } //語法錯誤
void average( double... numbers, String... times){ } //不能有一組以上的var-args
void average( double... numbers, char k ){ } //var-args必須是最後一個
Constructor宣告
- 建立新的obejct,最少會有一個constructor會被呼叫
- constructor不能有return type
- 可以有access modifiers,var-args
- constructor的名字必須和class名字相同
- constructor不能被標示成static(因為和object initialization有關係), final, abstract (因為不能被override)
// 非法建構子
void Foo2() { } // 不能有回傳type
Foo2(short s); // abstract method
Foo2(int... x, int t) { } // 錯誤的 var-arg 語法
variable的宣告
兩種type的variable
- Primitives: 共八種:char, boolean, (byte, short, int, long)整數, (double, float)浮點數,強型別,宣告後無法更改
- Reference variables: refer to 一個object。可為任何宣告class,也可以是宣告class的subclass (多型)
基本資料的宣告和範圍
- Java的六種數字型別(byte, short, int, long, double, float)都是某種數量的8-bit bytes組成,且帶正負號
- 以下範圍,正數個數之所以比負數個數少1,是因為0被歸類到正數
- VM決定boolean的值需要幾個bits表示
- 一個char包含16 bites萬國碼字元(0-2^16-1=65535); ASCII只需要8 bits表示,但需要其他空間表示非英文字元
Bits
|
Bytes
|
Minimum Range
|
Maximum Range
|
|
byte
|
8
|
1
|
-2^7
|
2^7-1
|
short
|
16
|
2
|
-2^15
|
2^15-1
|
int
|
32
|
4
|
-2^31
|
2^31-1
|
long
|
64
|
8
|
-2^63
|
2^63-1
|
float
|
32
|
4
|
n/a
| n/a |
double
|
64
|
8
|
n/a
| n/a |
Instance Variables
- 被定義在object class內,method之外,只有當一個class被initialization的時候才會進行initial的動作。
- instance variable是每個獨一無二的object的資料欄位(fields)
- instance variable = field = property, attribute
以下幾點注意
- 可以使用任何四種Aaccess等級
- 可以被標示為final/transient
- 不可被標示為abstract/synchronized/strictfp/native/static(class variables)
Local/Automatic/Stack/Method variables
- local variable 只宣告在method裡
- 所有的modifier只有final允許出現在local variable
- local variable只存在於stack,而不是在heap
- local宣告的object在stack內為local declared reference variable,沒有local object
- shadowing範例如下
int count = 9
void logIn(){
int count = 10
println(x)
}
logIn();//顯示10
println(x);// 顯示 9
- 使用shadowing的原因:要將parameter設定到instance variable上,如:
int size = 27;
public void setSize(int size) {
this.size = size; // 使用this解決naming collision
}
陣列的宣告
- Array本身是Heap裡面的一個object
- 宣告方式: 儲存的type+中括號+變數 ex: Thread[] threads; //增加程式可讀性,thread是(Thread[])的object reference
- 多維陣列 (multidimensional arrays),意指array的array
- Thread[][][] threads; //三維array(建議寫法)
- Thread[] threads[]; //二維array,合法但不是好的寫法
- Declare array的同時不能declare array大小,這不合法。 ex: int[5] count; //錯誤,必須要等到初始化array object,JVM才會分配記憶體,這時候才需要考慮array大小。
Final 變數
- 沒有final object, 只有final reference
- final的object reference variable可以修改這個object的資料,但不能再把這個reference拿去pointer其他object。
- Final v.s. Class : final class不能被extends
- Final v.s. Method: final method不能被override
- Final v.s. Variable: final variable一旦被initial,就不能再assign新值。(assign value必須在constructor執行之前發生)
Transient 變數(只能在instance variable上)
- 若instance variable標示為transient,表示JVM需要在serialize(序列化)時要忽略此變數
- serialized: 可以flattern(平坦化) object的status(instance variable)到一個I/O上。也就是可以將object存到檔案上,或讓它在網路上傳送,並在另一端JVM回復成原來的object(reinflating, deserializing)。
Volatile 變數(只能在instance variable上)
- 當一個thread存取帶有Volatile變數時,必須將thread對於此variable的copy和memory裡面主要的copy進行同步化。
- 為了保證資料是thread-safe,應該使用synchronized,而不是volatile modifier。
Static 變數和函式
- 如果class內的某些,method和variable與建立的instance無關,則可以使用static建立method/variable
- static method不能直接存取自己class的instance variable,因為他沒有和特定的instance有關係
- 建立任何class的instance之前,static member已經存在
- 不論有多少個instance,static member只會有一份
- 意即: 此type的所有instance都share同一份static variable
- 可以被標示為static:
- Method
- Variable(非區域)
- 包含在另一個class內的class(nested class),但不是在method內
- Initialization blocks
- 不可被標示為static:
- Constructor
- Class (Unless it is nested)
- Interface
- method local inner classes
- Inner class method and instance variable
- local variable (重要) local就是宣告在method內部的變數
Enums 的宣告
- Java5.0開始可以對variable的值加以限制,從某些定義好的清單中選擇一個來指派給variable(清單項目為enums),可以協助減少程式內的錯誤
Ex:
public enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
取得方法:
Day day = Day.MONDAY;
- 對enum來說,清單中的值都是常數,根據Sun的程式碼慣例:[應使用大寫字元和底線做為區隔(ex: MIN_HEIGHT)。]
- enum可以被宣告成獨立的class或class member,但它不能被宣告在method內
- emum只能宣告成public或default access level,就像non-inner class
- enum的後面不一訂要加分號
寫法一 (在class外,被當作是一個獨立class來宣告)
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}; //分號非必須
class Week{
Day date;
}
Week wk = new Week();
wk.date = Day.Monday;
寫法二(在class內,被當作是一個class member)
class Week{
enum Day {
SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
THURSDAY, FRIDAY, SATURDAY
}
Day date;
}
Week wk = new Week();
wk.date = Week.Day.Monday;
- SUNDAY, MONDAY, TUESDAY, WEDNESDAY,..這些都是Week的instance
- 可以將Day的enum想成一個Day的陣列,有順序性
- 其實對於SUNDAY, MONDAY, TUESDAY,..都是public static final,所以都是常數不可變
宣告enum 的contrcutor, method, variable
- 可以對enum增加Constructor, instance variable, method, constant specific class body(常數特定類別本體)
- 比如星期,對SUNDAY來說是7, MONDAY是1...所以還需要有常數,最簡單的方法是將每一個enum的值當作可以擁有instance variable的object。如此藉由initial enum的時候傳入constructor的arguments,可以指派每個object對應的值。
- 每個enum都有一個static method: value()
enum Day {//沒有括號
SUNDAY(7),
MONDAY(1),
TUESDAY(2),
WEDNESDAY(3),
THURSDAY(4),
FRIDAY(5),
SATURDAY(6);
Day (int order) { //constructor
this.order = order;
}
private int order; //instance variable
public int getOrder() { //method
return order;
}
}
Class Week {
Day day;
public static void main(String[] args){
Week wk = new Week();
wk.day = Day.Sunday;
Week wk2 = new Week();
wk2.day = Day.Thursday;
System.out.println(wk.day.getOrder());//return 7
for (Day d: Day.values())//對Day來講其實就是一個array
System.out.prinln(d + " " + d.getOrder());
}
}
印出結果:
7
SUNDAY(7)
MONDAY(1)
TUESDAY(2)
WEDNESDAY(3)
THURSDAY(4)
FRIDAY(5)
SATURDAY(6)
- 關於enum constructor:
- 不可以直接呼叫enum的constructor(enum的constructor是根據定義在constant後面的argument直接被自動呼叫
- enum的constructor可以接受多個argument
- 可以在enum定義constant specific class body
- 關於constant specific class body,想像以下情境:假設一星期只有禮拜六是開心的,其餘都是不開心的,如果不想在getMood()內使用if/else程式碼,最好是讓SATURDAY可以多載getMood()這個function並回傳"Happy"
enum Day { SUNDAY(7), MONDAY(1), TUESDAY(2), WEDNESDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6){//開啟一段程式碼,定義constant specific class body public String getMood(){ return "Happy"; } };//下面還有程式碼就必須加上這個分號 Day (int order) { //constructor this.order = order; } private int order; //instance variable public int getOrder() { //method return order; } public String getMood(){ //這個method被constant overloading return "Unhappy"; //這是default值 } }
沒有留言:
張貼留言