Lab:
實作一個建構子
修改
Product.java
加上建構子
public
class Product{
private
int id;
private
String name;
private
double unitPrice;
private
boolean free;
private
int stock;
//建立建構子
//手動建立預設的建構子
public
Product(){}
//建立一個建構子可以傳遞所有的類別
public
Product(int id, String name, double unitPrice, boolean free, int
stock){
this.id
= id;
this.name
= name;
this.unitPrice
= unitPrice;
this.free
= free;
this.stock
= stock;
}
//建立一個建構子可以傳入
id
以及 name
並利用 overload
的方式
public
Product(int id, String name){
//this(id,
name); 這樣會造成
recursive
constructor invocation, 所以要將後面的參數補上初始值,
才是呼叫別人,
不然只放兩個會在自己的方法產生迴圈
//所以String
的初始值是
null
//double
的初始值是 0.0
//boolean
的初始值是
false
//int
的初始值是 0
this(id,
name,0.0,false,0);//所以如果要呼叫上面那個,
這邊就要補到
5
個參數,
以此類推
}
//id
public
int getId(){
return
this.id; //這邊忘記使用
this.id
}
public
void setId(int id){ //注意
set的時候不需要回傳
this.id
= id; //所以只有在設定的時候會用到
this
}
//name
public
String getName(){
return
this.name;
}
public
void setName(String name){
this.name
= name;
}
//unitPrice
public
double getUnitPrice(){
return
this.unitPrice;
}
public
void setUnitPrice(double unitPrice){
this.unitPrice
= unitPrice;
}
//free
public
boolean isFree(){
return
this.free;
}
public
void setFree(boolean free){
this.free
= free;
}
//stock
public
int getStock(){
return
this.stock;
}
public
void incStock(int amount){
//stock
= stock + amount;
this.stock
+= amount;
}
public
void decStock(int amount){
this.stock
-= amount;
}
public
String toString(){
//剛剛發生使用單引號來包覆
\t
產生與 id
相加的現象
return
id + "\t" + name + "\t" + unitPrice + "\t"
+ free + "\t" + stock;
}
}
修改
TestProduct.java
public
class TestProduct{
public
static void main(String[] args){
Product
p1 = new Product();
//當改成
private
之後,忘記如何去存取
Product.java
內的方法
p1.setId(1);
//使用方法呼叫
前面加上方法名稱,傳遞參數進去
p1.setName("可口可樂");
p1.setUnitPrice(12.0);
p1.setFree(false);
p1.incStock(10000);
Product
p2 = new Product();
p2.setId(2);
p2.setName("百事可樂");
p2.setUnitPrice(10.0);
p2.setFree(false);
p2.incStock(10000);
/* p1.id=1;
p1.name="可口可樂";
p1.unitPrice=12.0;
p1.free=false;
p1.stock=10000;
p2.id=2;
p2.name="百事可樂";
p2.unitPrice=10.0;
p2.free=false;
p2.stock=10000;
*/
//利用建構子來新增
//好處是不用一行一行寫,
可以一次將參數傳進去
Product
p3 = new Product(3,"芬達汽水",13.0,false,12000);
//庫存價值
double
totalInventory = 0.0;
ProductService
ps = new ProductService();
//逐項將各品項相加
totalInventory
+= ps.calcProductInventory(p1);
totalInventory
+= ps.calcProductInventory(p2);
totalInventory
+= ps.calcProductInventory(p3);
System.out.println("庫存報表");
System.out.println("------------------------------------------------");
System.out.println("序號\t品名\t\t單價\t免費\t庫存量\t\t庫存價值");
System.out.println("------------------------------------------------");
System.out.println(p1+"\t"+ps.calcProductInventory(p1));
System.out.println(p2+"\t"+ps.calcProductInventory(p2));
System.out.println(p3+"\t"+ps.calcProductInventory(p3));
System.out.println("------------------------------------------------");
System.out.println("\t\t\t\t
庫存價值=
"+totalInventory);
System.out.println("------------------------------------------------");
}
}
*檢視物件建立的過程
- 當執行到 new ClassName(...)時
- 依造類別的定義在 HEAP Memory 配置物件記憶體
- 根據資料型別設定屬性的初值
- 將程式中明確宣告的初值指派給屬性
- 執行建構子程式, 完成物件的建立.
- 透過 new ClassName(...) 回傳該物件的參考.
Notes:
- 在類別表內 <<R/W>> 代表要提供 getter 與 setter 的方法
MyDate |
-
day: int =1 <<RW>> - month: int = 1 <<RW>> - year: int = 2000 <<RW>> |
+
MyDate(day: int, month: int, year: int) + toString() |
如果執行
MyDate
d = new MyDate(26, 9, 2012);
Step1:
MyDate
d = new MyDate(26, 9, 2012);
會準備一個
32
bits 的空間給 d,
準備存放物件的參考指標.
Step2:
MyDate
d = new MyDate(26, 9, 2012);
在Heap
裏面規劃記憶體空間,
並完成預設的初始化(根據屬性)
day
初始化0,
month 初始化0
將 year
初始化為 0,
Step3:
MyDate
d = new MyDate(26, 9, 2012);
完成明確初始化,
將 day
設定成1,
month 設定成1
將 year
設定為 2000,
Step
4:
MyDate
d = new MyDate(26, 9, 2012);
呼叫建構子並完成物建的建構過程
將 day
設定成26,
month 設定成9
將 year
設定為 2012
完成參考指標並對應到
d
Notes:
- Java 的變數的型別只要是類別, java 一律配置 32bits 空間
*Pass-by-value
- Java 使用 Pass-by-value 只有在
- 指派變數值
- 呼叫方法傳遞參數值
- 當指派的變數型別或傳遞的參數型別為 Primitive Type, 則傳遞的參數值為資料
- int a = 100; //a 為 100
- int b = a; // a 複製自己的資料給b
- b = 200;
- 當指派的變數型別或傳遞的參數型別為 Reference Type,則傳遞的參數值是HEAP Memory 中的參考
- MyDate d1 = new MyDate(26,9,2012); //建立指標(例如 0x12345678) 並值傳給 d1
- MyDate d2 = d1; //d1 將指標複製給 d2, d2 指向 0x12345678
- d2 = new MyDate(25,12,2012); d2 產生一個新的指標, 並指向新的指標
Notes:
- Java 只有 Pass-by-value
Lab:
觀察Pass-by-value
MyDate.java
public
class MyDate {
private
int day=1;
private
int month=1;
private
int year=2000;
public
MyDate(){}
public
MyDate(int day,int month,int year){
this.day
= day;
this.month
= month;
this.year
= year;
}
public
void setDay(int day) {
this.day
= day;
}
public
int getDay() {
return
this.day;
}
public
void setMonth(int month) {
this.month
= month;
}
public
int getMonth() {
return
this.month;
}
public
void setYear(int year) {
this.year
= year;
}
public
int getYear() {
return
this.year;
}
public
String toString(){
return
this.year+"-"+this.month+"-"+this.day;
}
}
Pass.java
public
class Pass{
public
void changeIntValue(int value){
value
= 500;
}
public
void changeObjectReference(MyDate ref){
ref
= new MyDate(25,12,2010);
}
public
void changeObjectValue(MyDate ref){
ref.setDay(6);
ref.setMonth(3);
}
}
PassTest.java
public
class PassTest{
public
static void main(String[] args){
int
a=100;
Pass
p = new Pass();
p.changeIntValue(a);
System.out.println("a="+a);
MyDate
d = new MyDate(26,9,2012);
p.changeObjectReference(d);
System.out.println("d="+d);
p.changeObjectValue(d);
System.out.println("d="+d);
}
}
Lab:
觀察 java
程式如何運作
利用
Point2D.java
與 TestPoint.java
來觀察
Key
Point:
- Java 在執行任何方法前, 會先將該方法掃描一遍, 然後將該方法所需的區域變數配置到堆疊
- 任何非 static 的方法, Java 一律會配置一個 "this" 的隱含變數給該方法.
- static 的方法不會有 this 的隱含變數.
- this 存著自己的指標指向記憶體的物件
- 如果堆疊變數沒有直接或是間接的指向 Heap, 最後會被回收
*宣告
import
- 類別中要使用不同package的其他類別, 在宣告或是建立時必須寫出 Fully Qualified Class Name
- 下列類別不需要 import
- 同一個套件的類別
- java.lang.* 中的類別
- package 命名建議使用 domain name + 系統結構
- 類別一旦帶有套件名稱, 名稱就會是package 名稱加上 類別名稱
- 寫import 是提供 JVM 或是編譯器搜尋的類別管道, 預設的搜尋路徑是 . (目前的目錄)
架構設計
myProject
|----src
|****|----com
|*********|----max
|**************|----
main/ Hello.java
|********************|----
model/ Greeting.java
|----classes
|****|----com
|*********|----max
|**************|----
main/ Hello.class
|********************|----
model/ Greeting.class
Hello.java
package
com.max.main;
import
com.max.model.*; // 提供JVM
或是 編譯器搜尋的管道,
要在 com目錄的上一層編譯
public
class Hello{
public
static void main(String[] arg){
System.out.println("Hello
world");
Greeting
x = new Greeting();
x.sayHello("Max");
}
}
Greeting.java
package
com.max.model;
//執行的時候一定要在相對的根目錄才可以使用
public
class Greeting {
public
void sayHello(String name){
System.out.println("Hello,"+name);
}
}
Notes:
- javac -d ../classes com/max/main/Hello.java (在src 目錄下指令)
- -d 指定輸出路徑 在上一層的 classes, 會將產生的class 對應到相對路徑
- java com.max.main.Hello (在classes 目錄下指令執行)
- java -classpath 以及 -cp 都是提供正確的 class path (類別開始起算的路經)
*.jar
檔的製作
- 使用 zip 來壓縮, 然後變更名稱為 *.jar
Bootstrap
Classloader (Java 的類別載入機制)
- %JAVA_HOME%/jre/lib/rt.jar
- rt.jar 是Java 所有的核心類別
- %JAVA_HOME%/jre/lib/ext/*.jar
- 讓廠商有機會換掉 jre 預設的核心類別
- System Loader
- 設定 CLASSPATH環境變數
- CLASSPATH=xxxx;xxxx;xxxx;xxxx;
- Windows 使用 ; 當分隔符號
- Unix like 使用 :當分隔符號
- 路徑的部份
- 可以指向類別起算的相對根目錄
- 或是指向 jar 檔的完整路徑 + 檔名
- 執行或是編譯的時候, 下達 -cp 或是 -classpath 指定類別搜尋路徑
- 例如jar檔放在 C:\myapp\lib下, 在C:\ 下達指令 (以windows 來說)
- java -cp c:\myapp\lib\maxlab.ja;c:\myapp\lib\test.jar com.max.main.Hello
沒有留言:
張貼留言