JAVA程式語法_物件導向Part2_static關鍵字使用之便利_final關鍵字使用


static關鍵字使用之便利

各位還記得之前分享了 JAVA OOP

我們拿了  車子  來進行比喻

這次一樣
假設我們是一個顧車的人士
我們有很多台車子要顧


那由於我們顧車會需要得知許多車子各自的特性

哪一廠牌
哪一車款
總價多少
里程數多少
車子的持有人是誰



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaoop;

/**
 *
 * @author chous
 */
public class Car {
    //Properties
    String Type;
    int Model;
    double Price;
    double Mileage;
    String Owner;
    
    public Car(){
        
    }
    
    public Car(String Type,int Model,double Price,double Mileage,String Owner){
        this.Type = Type;
        this.Model = Model;
        this.Price = Price;
        this.Mileage = Mileage;
        this.Owner = Owner;
    }

    //Methods
    double GetPrice(){
        double NewPrice = Price-(Mileage*100);
        return NewPrice;
    }
}






假設
其中有一個金主  太有錢了
叫做  Charles  一次要我們顧100台車
此時有沒有發現
我要去對每次新建立的車子物件中Owner屬性
重複設置相同的字串內容  "Charles "


那是非常麻煩的
因此在此  static 關鍵修飾字就能發揮不錯的功用
我們再針對 Owner 屬性多添加一個static修飾  於前方
建構子再多增設一個 overload 模式(多塞入一個Owner) 留為彈性


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaoop;

/**
 *
 * @author chous
 */
public class Car {
    //Properties
    String Type;
    int Model;
    double Price;
    double Mileage;
    static String Owner;
    
    public Car(){
        
    }
    
    public Car(String Type,int Model,double Price,double Mileage){
        this.Type = Type;
        this.Model = Model;
        this.Price = Price;
        this.Mileage = Mileage;
    }
    
    public Car(String Type,int Model,double Price,double MilesDrive,String Owner){
        this.Type = Type;
        this.Model = Model;
        this.Price = Price;
        this.Mileage = MilesDrive;
        this.Owner = Owner;
    }
    
    //Methods
    double GetPrice(){
        double NewPrice = Price-(Mileage*100);
        return NewPrice;
    }
}





透過 static 屬性定義預設值內容為 大金主(大多數車子屬於他)

static 可以簡單來說
就是預設給予一個值可供
多個用同一個class所建立出來之多個實體  能夠共享此內容
有一種大家分杯羹 的概念
因此不需要額外特別重複100次去針對每個新的車子物件實體去做同樣屬性內容的賦值




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaoop;

/**
 *
 * @author chous
 */
public class JavaOOP {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        Car.Owner = "Charles"; // static variable difinition can be shared default value in muti-class
        
        Car car1 = new Car();
        car1.Type = "BMW";
        car1.Model = 2016;
        car1.Price = 9000;
        car1.Mileage = 15;
        //car1.Owner = "Charles";
        System.out.println("Owner of car1:" + car1.Owner);
        
        Car car2 = new Car("BMW",2018,10000,5);
        System.out.println("Owner of car2:" + car2.Owner);
    }
}


再看一個例子  加深  對於  static 類別成員
的一些觀念

一個 球(Ball) 物件
我們可能會去定義 查看其
半徑  (R)
圓周率(PI)
球體體積(4/3 * PI * R^3)
球體表面積(4 * PI * R^2)


在此我們都知道  圓周率為固定的常數數值
不用每個物件實體各自都擁有存取權
因此可改為 以 static 前綴來修飾


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaoop;

/**
 *
 * @author chous
 */
public class Ball {
    double radious;
    //double PI ;//3.14159265359
    static final double PI = 3.14159265359;
    
    
    public double getVolume(){
        double v = (4/3) * this.PI * Math.pow(this.radious, 3);
        return v;
    }
    
    public double getSurfaceArea(){
        double s = 4 * this.PI * Math.pow(this.radious, 2);
        return s;
    }
    
}

這裡的
static final double PI = 3.14159265359;
代表它只屬於Ball此類別(物件之設計藍圖)
換言之在使用上不需要先宣告實體化才能調用
而是直接以類別.XXX
去直接呼叫使用


PS:有時我們在處裡分析開發問題時,會需要多個以上的類別在同一個內存區塊
共享同一個資料內容。

若有觀賞過 JAVA  Math Class內部構造的  程式人員
就知道在  JAVA  Math 中
定義到的   圓周率(PI)  和  尤拉數(e)
甚至是一些常用固定計算公式方法
三角函數  或是 toRadians 、 toDegrees 等方法
這些類別成員
都是使用 static 為前綴作為修飾的



也因此在使用 Math 時

你只會看到  Math.pow  ....  , Math.toRadians  , Math.floor ......

而不會看到會寫這樣
Math m1 = new Math();
m1.pow ....

詳細  Math常用的方法可以參考之前寫的一些簡單介紹文

JAVA程式語法_數學運算



Ball 物件 例子輸出結果




 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaoop;

/**
 *
 * @author chous
 */
public class BallMain {
    public static void main(String[] args) {
        System.out.println(Ball.PI);
        
        Ball b1 = new Ball();
        //Ball.PI = 3.14;
        b1.radious = 3;
        System.out.println("半徑3之球體");
        System.out.println("體積:"+b1.getVolume());
        System.out.println("表面積:"+b1.getSurfaceArea());
    }
}




所以下次只要是看到有static關鍵字出現的屬性、方法
就可以知道其使用時的一些外觀長相
甚至可以藉此反推其為  static修飾


通常  使用 static 修飾  出現  就代表
類似剛剛最一開始所提的

大金主 一次託付一百台車要我們顧這樣子的設計
也就是  大家都分同樣一杯羹

再來是 其使用上可能也是類似Java Math Class 設計原理
主要是設計成一個會時常被調用呼叫等功能小型單元
會被大量重複使用因此被包起來還有預設內容數值等等


Static可幫助我們解決實際開發工作上的常遇問題

static修飾 可以幫助我們做到的事情還有很多
不僅僅只是簡化還要多實體化這個步驟(Java Math概念)
或是預設值(共分一杯羹)等等概念



新客戶會員註冊ID累加更新課題
以下方我們再舉一個例子
假設我們今天要實作一個類別是關於
Customer 客戶  Class設計

那這裡我們定義
客戶姓名
客戶ID編號
兩個屬性
那每次我們一有新客戶註冊會員卡等等之類的
我們的  ID編號  就遞增1
類似此工程設計目標


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaapplication9;

/**
 *
 * @author chous
 */
public class JavaApplication9 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        Customer a = new Customer("Ken");
        Customer b = new Customer("Jack");
        Customer c = new Customer("Bob");
        
        System.out.println("Name:"+a.name +"\nID:" + a.id);
        System.out.println("Name:"+b.name +"\nID:" +b.id);
        System.out.println("Name:"+c.name +"\nID:" +c.id);
    }
}
class Customer{
    String name;
    int id = 0;
    
    Customer(String name){
        this.name = name;
        id+=1;
    }
}


那你會發現輸出結果則是每次的ID都還是固定為1不變

因為每次只要一產生新物件
對電腦而言就會重新做累加的計算!!!!!
各個新生成之物件是不會知道各自的ID的!!! 對它們而言每個人ID都是各自新建出來的
所以不會去得知其它客戶物件實體的ID
所以每次累加的屬性ID都是從0開始的
ID每次都是會刷新紀錄的 ,不會讓下一筆新物件得知上一筆狀態!!!!!!



如果我想要維持某個Class屬性
對每個新產生出來的各個新物件實體
不重頭來過的話!!! 換言之,可以讓多個透過同一個Class設計所生成的眾多實體
都能認識並且可共享的變數屬性的話
此時就須要透過建立新的一個  static修飾之變數去記憶

所以現在   輸出結果有被修正了


=============================================================

最一開始實體化出來的新客戶物件 Ken
(若覺得抽象就想像是  新的會員註冊)

Ken  實體


客戶Ken            --> ID : 0   nextID : 1


nextID指派給ID --> ID : 1   nextID : 1


nextID做加1      --> ID : 1   nextID : 2



Jack 實體


再來新進來的會員  Jack
對它而言已經知道的  ID 還是為 0   但是有看到嗎  nextID有紀錄到上次變更之紀錄
所以即便ID 每次都從0開始也沒關係   因為後續我們是透過nextID去累加更新
客戶編號的喔!!!!! 所以新加的  static 屬性nextID  妙用就在這裡
它可以讓下次新生成的物件得知上一個物件的一些狀態紀錄值


所以下一個  就會知道上一物件Jack 於建立過程 已經將nextID狀態紀錄值更新為3了



改寫成物件陣列


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javaapplication9;
/**
 *
 * @author chous
 */
public class JavaApplication9 {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        
        Customer[] objArray = new Customer[3];
        for(int i=0;i<objArray.length;i++){
            objArray[i] = new Customer("Jack"+i);
            System.out.println(objArray[i].name);
            System.out.println(objArray[i].id);
        }
        
        
//        Customer a = new Customer("Ken");
//        Customer b = new Customer("Jack");
//        Customer c = new Customer("Bob");
//        
//        System.out.println("Name:"+a.name +"\nID:" + a.id);
//        System.out.println("Name:"+b.name +"\nID:" +b.id);
//        System.out.println("Name:"+c.name +"\nID:" +c.id);
    }
}
class Customer{
    String name;
    int id = 0;
    static int nextID = 1;
    Customer(String name){
        this.name = name;
        id = nextID;
        nextID++;
        //id+=1;
    }
}






static 修飾的相關內容使用常出現錯誤


我們已經知道
(1)凡是用static所修飾的成員,都是只屬於類別的 , 只有類別具有存取權
(2)在使用上不需要先宣告實體化才能調用,而是直接以類別名.XXX 去呼叫
(3)物件屬性若非static的就不會有紀錄上次狀態值  (共享狀態紀錄)
其實還有第四點要注意也因此
不可以在有使用static修飾之區域(static method)
使用非static修飾的內容(比方this .... 和 非static的方法)

例如





final關鍵字使用


為何剛才的 PI  前方要多加個 final呢??

意思就是要其值內容就是一個固定不變的常量(數)

比方說如果你對  剛剛我們所定義之  PI
想指派給它  3.14
就會報錯

所以如果你在接手一些前人專案時
假若有一些類似 字串前方也有放上final等修飾

可能是指某個固定檔案所在路徑 、檔案預設要產生之位置、檔案要發送之目的地等等之類的
可能是一個寫死的值

建議不要亂去更動 !!!!!!!


透過一些語法特性細節可以幫助我們
更加瞭解當時前人為何這麼寫喔 !!!!!




















留言

這個網誌中的熱門文章

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header

經得起原始碼資安弱點掃描的程式設計習慣培養(三)_7.Cross Site Scripting(XSS)_Stored XSS_Reflected XSS All Clients

(2021年度)駕訓學科筆試準備題庫歸納分析_法規是非題