Class

24 April 2020

Class

class定義一組variable,和method(function)。

  1. local variable(method內變數)是在method被啟動時allocate,method結束後消失,或是在大括號內執行,大括號內結束後消失(在大括號內宣告)
  2. method parameter如果跟傳進去的type不同時會自動casting,例如需要double,傳進去int會自動cast成double
  3. Java沒有global variable
  4. Java class裡面的method沒有forward reference問題,也就是說,我可以先使用某method,但在後面才宣告該method。
  5. class的method能夠使用、呼叫同個class內其他object,如下
public boolean equals(Date otherDate){
    if(this.date == otherDate.date)    return true
}
object是可以直接取得同個class其他object的private variable,而不用用accessor
  1. 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

注意

  1. 不要跟type cast搞混,有時候呼叫method我們利用type cast將參數轉成我們想要的形式,但是如果已經有那個overload method,那反而會執行該method而不是原本method+typecast,而且有時候overload配上typecast會confuse。
  2. return值不同不能當作overload
  3. Java不能overload operator,C++可以

Reference

override & overload overload

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

Reference

在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>
  1. static method不能用this,因為他不用object就可以invoke(他不屬於任何Object,屬於class)
  2. 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

  1. public : 因為jvm要能夠執行main function,所以要是public
  2. 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外不能修改(也就是不能..set...),但可以透過get取得位址後用其他function來改private, variable.set...),但可以透過get取得位址後用其他function來改private variable的值。 例如

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或與原物件相關