Class
24 April 2020
Class
class定義一組variable,和method(function)。
- local variable(method內變數)是在method被啟動時allocate,method結束後消失,或是在大括號內執行,大括號內結束後消失(在大括號內宣告)
- method parameter如果跟傳進去的type不同時會自動casting,例如需要double,傳進去int會自動cast成double
- Java沒有global variable
- Java class裡面的method沒有forward reference問題,也就是說,我可以先使用某method,但在後面才宣告該method。
- class的method能夠使用、呼叫同個class內其他object,如下
public boolean equals(Date otherDate){
if(this.date == otherDate.date) return true
}
object是可以直接取得同個class其他object的private variable,而不用用accessor
- local variable不會initialize,instance variable(class內變數)會initialize
this
在class內的method,當呼叫像是
public void writeOutput(){
System.out.println(month+day)
}
其實等於
public void writeOutput(){
System.out.println(<object>.month+<object>.day)
}
因此在class的method撰寫時,使用this來代表現在這個class的object 因此可以這樣寫
public void writeOutput(){
System.out.println(this.month+this.day)
}
在initial或set variable時最常見
當某class有一個date參數,要把parameter的date值給class內的date
時要這樣寫
public void setData(int date){
this.date = date;
}
如果直接寫date=date不會賦予class內的date值
testing
要測method有沒有bug
driver program
用來測試method的程式
bottom-up testing
如果method彼此之間有互相invoke,測試要給其他人呼叫的method慢慢測到呼叫其他method的method,buttom-up
encapsulation
把class、method包成一個物品,雖然外面使用者不知道implement細節,但是他可以直接呼叫這個class的函式。一來達到information hidden,二來讓使用者更方便使用(因為有良好介面,使用者照著說明做即可,不用去看class的實作)
accessor & mutator
因為encapsulation,我們會把class內的變數設為private,外人不能直接更改變數值,所以就需要一個accessor來回傳變數值
一個mutator來設定變數值。通常就是method started with get or set。mutator會做一些檢查再設值,所以跟直接把變數設成public不同。
Overload
同個method名字,但參數不同。
要有不同的signature(即tuple(method名,參數))要不同
method signature(method名,參數)中的參數要不同
只有return值不同不能overload
注意
- 不要跟type cast搞混,有時候呼叫method我們利用type cast將參數轉成我們想要的形式,但是如果已經有那個overload method,那反而會執行該method而不是原本method+typecast,而且有時候overload配上typecast會confuse。
- return值不同不能當作overload
- Java不能overload operator,C++可以
Reference
Constructor
用來intialize object的變數 如果自己沒定義constructor,會使用Java自己default的constructor,如果有定義constructor,Java就不會有default constructor,所以自己定義的話,要自己寫一個No-Argument Constructor。
建立constructor
public class <filename>{
public <filename>(...){...};
}
Destructor
C++ new的東西要delete來free掉記憶體空間
但Java沒有destructor的東西因為Java有自己的garbage collection機制, 會在一些特殊條件下檢查object未來還會不會用到,用不到就回收記憶體
所以Java create物件或東西是不用自己去把它delete/free掉的
initialize也可以直接在宣告變數時給值
StringToeknizer
在java.util裡,用來切割字串的,像python的split
StringTokenizer a = new StringToeknizer("hello world")
while(a.hasmoretoken())
System.out.println(a.nextToken())
Static
在function內的static變數
代表一直存在,不會隨著function結束而被清掉
function外的static變數
只在這個檔案裡有效的全域變數
class內的static變數
代表所有object共用該變數,static的變數會在宣告時自動initialize
class內的static函式
代表該函式不用產生object後就能呼叫,但是在實際呼叫時Java的關係仍要在前面放上class name。static function仍屬於該class。故也可以創一個object在invoke static function。
<classname>.maximum();
EX : System.exit() -> static method,不用產生System Object
non-static:
this.<method/variable>
static:
static method不用object也能呼叫
<classname>.<method/variable>
- static method不能用this,因為他不用object就可以invoke(他不屬於任何Object,屬於class)
- static method不能做呼叫object的動作(像存取object的instance變數),但可以存取class內的static variable,static method應該在即使沒有object時也能呼叫(除非function裡面new一個新的object在call method)
private static int turn = 0;
public static int getTurn(){
turn++; =>因為turn是static variable所以可以直接access
return turn;
}
public static void main
- public : 因為jvm要能夠執行main function,所以要是public
- static : 因為main是在object產生前執行,故需要宣告static,使此函式不用產生object就能呼叫
Wrapper class
將primitive type轉成object
注意: primitive type沒有null值,object才有null值,所以wrapper class才
有null值,
wrapper class沒有 null constructor(一定要參數給值,不能空白!!!)
Integer 為int的wrapper class
而將primitive type轉成Wrapper class的過程叫boxing
Integer a = new Integer(42)
int b = a.intValue(); => 這個過程叫unboxing,把class轉成primitive type
Primitive | wrapper class | Primitive | wrapper class |
---|---|---|---|
int | Integer | byte | Byte,byteValue |
short | Short, shortValue | long | Long, long Value |
float | Float, floatValue | char | Character, charValue |
new wrapper class object時壹定要給值,不能給null
Integer a = null; 假設a已經是null了
Integer b = new Integer(a) => error
所以在oopjudge 第七題要注意
public Integer get(int index){
// 要先判定Arr[index]是不是null
// 如果是null 下一行的new(this.Arr[index])會錯
if(index >= this.size || this.Arr[index] == null) return null;
return new Integer(this.Arr[index]);
}
Automatic boxing
Java5.0後自動boxing的部分
Integer a = 47 等於create一個Integer object有著47這個值給a
Integer a = new Integer(47)
Automatic unboxing
同上,指示改成自動把object值賦予給primitive type
Integer a = 47;
int b = a; =>不用call method來給值
Wrapper class目的
定義許多primitive type常用的常數、函式 沒有non-argument constructor !!!! EX :
- Integer.MAX_VALUE(MIN_VALUE)
- Double.parseDouble(“100.123”)
- Double.toString(1.213)
Memory
- main memory存程式、變數,以byte的形式存,
- 資料是連續儲存,像int就是一次佔據4個連續的byte,此data chunk的第一個byte當做這個data存放的address
Reference
- primitive type的data因為大小固定,所以賦予值給一個變數時,是直接改該變數記憶體位置的值
- object因為大小不固定(跟class內有的東西量有關),因此當宣告一個object variable時,只存object locate的address位置,因此是像指標那樣,本地是指標指到真正object allocate的位置。
- 其實很單純,因為在產生class的object是用new的,所以依定是reference的形式
object a = new object();
object b = a
代表a,b variable位址都是存object的位置,
因此a,b對object的修改對方都看得到,指向同個object
comparsion
就上述所說,object是reference的形式,object的變數值是存記憶體位置,所以要比較兩個object的值還是要自己寫一個equal method。
== 的比較是比記憶體位置而不是比object內變數值
object a = new object(3)
object b = new object(3)
a == b
false
當要做object比較時,如果比較對象只是為了這次使用那就不用賦予一個變數給他
if(a.equals(new object(3))){...}
Call-by-value
Java的傳參數都是call by value的方式,把參數的值複製給function內的variable。
但是也因為object是reference的方式,所以當function參數為object時,其實是copy object的位址給parameter,所以function修改object值時,外面看到的object值也會改變。
null
就compiler要求initialize時設定 設成null的object不能invoke method (null pointer exception)
static import
對於static method,import時使用static就可以不用寫object.method,可以直接寫method
import static java.lang.Character.toUppercCase;
or import static java.lang.Character.*
Character.toUpperCase()
-> toUpperCase()
class invariant
class內的method,目的是做變數值得檢查,要return true,確保object的變數值是正確範圍(通常這個method設成private,在constructor裡檢查)
Copy constructor
就是constructor參數只有一個,就是object本身 這種方式要注意intialize的過程確保每個assign都是primitive type,因為class type會變成reference(改到一方,另一方的值也會改)。
public a(object a){
name = a.name => string是object,reference
// a改的話這個object的name也會改
// 應改成
this.name = new String(a.name)
}
privacy leak
在copy constructor或者get function時如果return的是一個object而且沒有用new的形式而是直接return 變數值。那等於是return了該變數的memory位置。攻擊者可以透過該object的method來修改object的值。 簡單來講就是透過get function取得private variable的位址後用set function來改private variable的值,這樣就會改到object的值。 private的variable在class外不能修改(也就是不能
Person citizen = new Person("jimmy",birth_date,Dead_date)
其中date都是Date object,
當有一個函式是
public getDate(String name){return this.birth_date}
攻擊者利用getDate可以得到jimmy的birth_date object
接者使用 citizen.getDate().setDate()就可以改變jimmy object的date值
比較好的寫法
public getDate(string name){
return new Date(this.birthDate);
}
Injection 2,在construct時,假設
setBirthDate(Date newDate){
this.Date = newDate
}
date = new Date()
object.setBirthDate(date)
date.setDate().... // 修改了object的date
結論就是記得只要是set,get method都要用new的形式,不要return mutable object的reference。或者該class本身就沒有set、修改值得method(String=> immutable objects),那這樣就算直接return也沒差,因為object值不能修改。
String a = "hello ";
a = a+ "world" -> 其實是產生一個新object有"hello world"的值,
原本的object不會被改變,只是沒人reference的話會被garbage collection
Immutable & mutable object
Name | Definition | EX |
---|---|---|
immutable object | 沒有method能修改值得object,不怕privacy leak | String |
mutable object | 有method能修改值得object,怕privacy leak | Date |
Deep copy & shallow copy
Deep copy : 新的物件沒任何mutable object是reference或與原物件相關