course introduction class iii. outline “equals” and “==“, the equality problem the root of...
Post on 19-Dec-2015
222 views
TRANSCRIPT
Course Introduction
CLASS III
Outline
• “equals” and “==“, the equality problem• The root of the class hierarchy• Modifier• Nested classes
– Instance nested class– Static nested class
1-2
1-3
Object equal?
• 比較兩個東西是否相等, JAVA 程式碼最常用到的方法不外乎下列兩種 :– “==“– 呼叫函式 equals()
• 普通的 data type 比較數值如整數,小數可利用簡單的” ==“ 來判斷相不相等
• 關於產生物件的 reference type 則採用” ==“ 來比對不一定正確
• 這是為什麼呢– l-value, r-value
Review This Figure
heap
objRef1=0x3200
objRef3=0x3288
objRef2=0x4650
(Object instances inside)intValue=3booleanValue=true
(Reference type variables)
(Primitive type variables)
objRef4=0x3200
objRef1==ObjRef4?
相等的問題
• “==“ 所比較的是 reference value• 真正判定二個”物件實體”是否相等,必須判斷
“物件當中的內容”– Ex: 二個學生物件,姓名,學號都一樣 應為同一人– 透過實作 public boolean equals(Object o) 來解
決
1-5
1-6
相等的迷思程式碼
class Student {String name;String id;
public boolean equals(Object obj) {Student otherStudent = (Student) obj;if( this.name.equals(otherStudent.name) &&
this.id.equals(otherStudent.id) ) {return true;
}else {
return false;}
}}
equals 這個方法
• 定義在 java.lang.Object 中• 原本的實作是比較 reference value 是否相同• 我們是去 “ override” 在 java.lang.Object
中的 equals
1-7
萬物之源: java.lang.Object
• Java 的設計當中,所有的物件都是這個物件的子類別– 將繼承關係以樹狀結構表示時, java.lang.Object 就
是 root!• http://java.sun.com/j2se/1.4.2/docs/api/jav
a/lang/Object.html
1-8
1-9
修飾字 • final 修飾子
– final 修飾子可以套用於類別、資料或是方法。– final 變數的值一旦設定之後,變數的值就不可更
改。– 使用 final 關鍵字可以避免此種情形
• 用在 method– 表示 method 無法繼續被 override
• 用在變數– 不能改變變數所 hold 之 value
» 對 primitive types 而言,“純量”不能更改» 對 reference type 而言,固定只能指向某個物件
• 用在類別– 表示此類別將無法再被其他類別繼承
1-10
Final Example
public class ConstantData{ public static void main(String[] args){ final int constantInteger=10; constantInteger=12; //error, can not assign!!}
public class ConstantReference{ public static void main(String[] args){ final Student stuObj=new Student(“John”); stuObj.setName(“Yoshi”); //OK!!}
1-11
Final Example
public class ConstantReference{ public static void main(String[] args){ final Student stuObj=new Student(“John”); stuObj = new student(“John”); //error!!}
Student Class 某個 Instance
final 限制的對象
非 final 限制的對象
1-12
Final Example
物件
生物
動物 植物
牛馬羊豬狗
花草
不會再有其他類別( 不會在往下延伸其他類別 )
final class Plant {}
1-13
修飾字• abstract 修飾子
– 若在類別加上 abstract 關鍵字,表示這個類別式抽象類別
– abstract 修飾子只可以套用於• 類別 (Class)• 函式 (Method)
– 宣告為 abstract 的類別,不能夠實體化 (new) 。– 如果類別中的方法使用了 abstract 修飾子,該方法
只有名稱、參數內容和回傳型別的定義,不能有實作的部份。
– 在類別中只要有一個成員方法使用了 abstract 修飾子,則該類別也必須使用 abstract 修飾子。但不需要將所有的成員方法都宣告成 abstract
1-14
abstract Example
abstract class Specification{ static final int constantInteger=10;
static final boolean OK=true; abstract void show(); void print(){
System.out.println(“….”);}
}
1-15
使用介面 (interface)
• 「介面 (interface) 」用來定義一套標準、規範– 讓程式的撰寫有一定的規則可遵循– 為物件之間的互動訂定規範
• 介面也可以被視為類別的一種– 不同:介面內只可以定義常數和抽象方法。
• 介面可以當作類別的收集器,可使用 extends 於interface ,以彌補 Java 中 Class 不允許多重繼承的性質。
• 介面只提供方法的定義而不實作該方法。– 不能用 new 來產生物件,因為介面沒有建構子
1-16
使用介面 (interface)
– interface 的基本架構
interface base1{ void fun1(args1,args2,…);}interface base2{ void fun2(args1,args2,…); }class sub1 implements base1,base2{ public void fun1(args1,args2,…){ … } public void fun2(args1,args2,…){ … }}
1-17
宣告介面 • 介面裡只宣告屬性和方法,沒有建構子。
inteface Actions {public String name = "Some Actions"; public void canFly();public void canRun();
}
會變 public static final
interface Specification{ int constantInteger; //error, 沒有宣告初始值 public static abstract boolean OK=true;
//error, 不能為 abstract 抽象…必為常數public static void show();
//error, 不能為 static 靜態…必為抽象}
會變 public abstract
1-18
實作介面 • 實作介面時,使用 implements 關鍵字
• Java 不允許 class 同時繼承多個類別,但可以同時實作多個介面。
• 當類別實作了介面後,該類別擁有介面中所有的方法和屬性。類別必需負責實作介面中的所有方法。– 因為介面只有抽象的方法
class Bird extends Animal implements Actions {}
class Bird implements Actions, Action2, Action3 {}
1-19
繼承
• interface( 介面 )– Java CLASS 裡沒有多重繼承,若要用到多重繼承,
必須以 interface 為替代方案interface abstract
多重繼承 有 無建構函數 不可以有 可以有
方法實作 必須全部由實作的類別實作可將全部或部分方法交由繼承的類別實作,或完全不給繼承的類別實作任
何方法
變數改變 變數必須給定初始值,之後使用不可更改,相當於加上 final 關鍵字 可以更改
變數繼承 有 有
1-20
繼承宣告
• extends 類別名稱– 宣告此類別是繼承其它類別而來。 Java 只允許單一
繼承,意即,每個類別最多只有一個父類別。• implements 介面名稱 , 介面名稱 ,…
– 宣告此類別需要實作其它介面以增加此類別的特性。
1-21
利用介面模擬多重繼承interface Action1 {
public void canRun();}interface Action2 {
public void canFly();}interface Action3 {
public void canSwim();}interface AllAction extends Action1, Action2, Action3 {}abstract class SuperAnimal implements AllAction{}class SuperDuck extends SuperAnimal{}
1-22
Error implements
interface USB{public void show();
public void print();}Class USBMouse implements USB{
//error // 因為 implement 介面必須定義清楚 show() 跟 print() 動作 ~~ 不能是抽象的 !!}public class Application{
public static void main(String agrs){USBMouse usbMouse = new USBMouse();
}}
1-23
Right implements
interface USB{public void show();
public void print();}Class USBMouse implements USB{
public void show(){System.out.println(“I’m USB Mouse”);
} public void print(){
System.out.println(“I’m moving”); }}
1-24
建立巢狀類別 • 巢狀類別 (Nested Class) 指類別中還有其他的類
別。– 外部的類別稱為「外圍類別 (Enclosing Class) 」
– 內部的類別稱為「巢狀類別 (Nested Class) 」。• 從外圍類別外使用內部類別:
– 外部類別名稱 . 內部類別名稱• 依照巢狀類別的存取特性,巢狀類別分為:
– 內部類別 (Inner Class)– 靜態內部類別 (Static Inner Class)– 局部內部類別 (local inner Class)– 方法類別 (Method local Class)– 匿名類別 (Anonymous Class)
1-25
內部類別 (Inner Class)
• Inner Class 是在外部類別中直接宣告的次類別,宣告方式和一般類別的宣告方式相同。– 最常使用的方式
• 可以用 private 、(default) 、 protected 、 public 等修飾字來定義 Inner Class 。– 如果 Inner Class 定義成 private ,外圍類別以
外的其他類別就無法使用該 Inner Class 了。
class OuterClass2{//Other Code Herepublic class InnerClass2{ }
1-26
Right implements
class Computer{ // 外圍類別 (Enclosing Class) class CPU{ // 內部類別 (Inner Class) 不能與外圍類別名字一樣
/…/ class mathPower{ // 內部類別 (Inner Class)
/…/}// end of mathPower class
}// end of class CPU}//end of Computerpublic class Application{ public static void main(String agrs){
Computer aComputer= new Computer(); // 須產生外圍類別Computer.CPU aCPU= aComputer.new CPU(); }
}
1-27
靜態內部類別 (Static Inner Class) • 宣告內部類別時,如果使用 static 修飾字,則該內部
類別稱為「靜態內部類別 」。• 靜態內部類別的記憶體位置獨立配置,不需要先將外圍類
別實體化就可以使用靜態內部類別。• 靜態內部類別通常是為了供其他的類別使用
– 在 Inner Class 內可以使用外圍類別的資料。– 在外圍類別內,必須先將內部類別實體化,才可以使
用內部類別的成員外圍類別 . 內部類別 物件名稱 = new 外圍類別 . 內部類別
1-28
靜態內部類別 (Static Inner Class)• 靜態內部類別無法直接存取外圍類別中的非static 成員。
• 靜態內部類別可有 static 成員和非 static 成員。– static 成員在載入時同樣也配置了記憶體空間,外界可以直接引用。
– 非 static 成員則必需要先將靜態內部成員實體化後才能使用。
1-29
靜態內部類別 (Static Inner Class)
可否直接使用外圍類別的static 成
員
可否直接使用外圍類別的非static 成員
可否直接讓外部直接存取
static 巢狀類別的
static 成員
可 否 可
static 巢狀類別的非static 成
員
可 否 否
1-30
error implementsclass Computer{
class CPU{ // 非 static 內圍類別/…/
static class mathPower { //static 內圍類別/…/
//error, can not 加入 static 內圍類別在非 static 內圍類別 但是可以加入非 static 的內圍類別在 static 內圍類別 ( 如下
頁 )}
}}
1-31
Right implementsclass Computer{
static class CPU{/…/
class mathPower {/…/
}}
}
1-32
Right implementsclass Computer{
static class CPU{/…/
interface FloatingCalculating {/…/
} static class mathPower implements FloatingCalculating{
/…/}
}}public class Application{ public static void main(String agrs){
Computer.CPU aCPU= new Computer.CPU(); //static inner class 只能直接搭配類別}
}
1-33
error implementsclass Computer{
static class CPU{/…/
interface FloatingCalculating{ /…/
} static class mathPower implements FloatingCalculating{
/…/}
}}public class Application{ public static void main(String agrs){
Computer aComputer= new Computer(); // 產生物件Computer.CPU aCPU= aComputer.new CPU(); //error, 只能直接搭配不可以搭配物件}
}
1-34
避開循環參考 • 「循環參照」是指兩個物件互相參考。
– 例如: A 物件是 B 物件的參考,而 B 物件又是 A 物件的參考。
• 循環參照使得物件佔用的資源不被回收,它們會一直佔用著記憶體直到程式結束為止。
• 避免循環參照常用的方法是:覆寫 finalize 方法,並在該方法中將指向其他物件的參考都設定為 null 。
1-35
Local inner classclass Device{
void showDeviceName(){}
} class StorageDevice{
Device makeHardDisk(final String devicename){ //class in the method
class HardDisk extends Device { void showDeviceName(){
System.out.println(“ 名稱” + devicename);
} }
return new HardDisk();}public class Application{ public static void main(String[] agrs){
Device devices=new StorageDevice().makeHardDisk(” 硬碟” );}
}
1-36
Local inner class
• Some syntax– How to refer to outer-class object?
• Use outer-object.this• Use this and super
1-37
Local inner class exampleclass Device{ // 外圍類別 (Enclosing Class)
String devicename=“裝置” ; boolean embedded=false;
void showMember(){ } class StorageDevice{ // 內部類別 (Inner Class) boolean embedded;
Device makeHardDisk(String manufacturer){ Class HardDisk extends Device{ //local Inner calss
void showMember(){super.devicename;StorageDevice.this.embedded;
}
}return new HardDisk();
}}
1-38
匿名類別 (Anonymous Class)
• 沒有宣告名稱的類別稱為「匿名類別 (Anonymous Class) 」。
• 宣告的方式是直接在程式中以 new 關鍵字來建立類別實體。
• 由於該類別並沒有名稱,因此只能使用一次。宣告匿名類別時也可以定義成員及方法,但是不可以定義 static成員,也不能定義建構子。
父類別名稱 物件名稱 = new 父類別名稱 ( 參數 ) {// 匿名類別中的成員與方法 ;
};
1-39
內部匿名類別可以不宣告類別名稱,而使用 "new" 直接產生一個物件,內部匿名類別可以是繼承某個類別或是實作某個介面,內部匿名類別的宣告方式如下:new [ 類別或介面 ()] {
// 實作 }
Object obj =
new Object() {
public String toString() {
return " 匿名類別物件 ";
}
};
重新定義 toString()
在檔案管理方面,內部匿名類別在編譯完成之後會產生「外部類別名稱 $編號 .class 」,編號為1 、 2 、 3...n ,每個編號 n的檔案對應於第 n 個匿名類別
編譯後產生AnonymousClassDemo.class 與AnonymousClassDemo$1.class
匿名類別
1-40
注意如果要在內部匿名類別中使用外部的區域變數,變數在宣告時必須為 "final" ,例如下面的陳述是無法通過編譯的:....
public void someMethod() {
int x = 10;
Object obj =
new Object() {
public String toString() {
return String.valueOf(x);
}
};
System.out.println(obj);
}
....
沒有宣告為 final
x 不能在匿名類別中使用
local variable x is accessed from within inner class; needs to be declared final
匿名類別
1-41
存取修飾字
• Use in Class– [ 存取修飾字 ]+class+ 名稱– Only public, default
• Use in Method– [ 存取修飾字 ]+[static]+ 傳回值 + 方法名稱
• Use in data– [ 存取修飾字 ]+ [static]+ 資料型別 + 名稱–區域變數中的生命週期僅存在於這個方法,方
法一但執行完畢,區域變數則自動歸還系統,因此區域變數不可加上 static
1-42
存取修飾字
• Public– 每各 class皆可存取
• Default– 同一個 package 的 class才可以存取
• Protected– 同一個 package 的 class才可以存取– 不同 package 但是如果有繼承也可存取
• 可以存取“繼承下來的”• Private
– 同一個 class才能存取
1-43
非存取修飾字• Final
– 防止被覆寫,通常用於已經制定好的 API• Abstract
– 抽象的概念,未被實作的程式碼– 通常用於開發階段的程式宣告
• Synchronized– 該函式對於此一物件,只能被一個執行緒執行存取
• Native(*)– 該函式與平台相關的程式碼
• Strictfp(*)– 浮點數遵循 IEEE754 的標準
1-44
參考資料
• 物件導向觀念– http://java.sun.com/docs/books/tutorial/java/concepts/index.html