-
定義函數
-
PL/SQL定義的類中,函數的定義有兩種方式;
- MEMBER型函數:該函數需要通過對象進行定義,使用MEMBER定義的函數可以利用SELF關鍵字訪問類中的屬性內容;
- STATIC型函數:該函數獨立於類之外,可以直接通過類名稱進行調用,使用STATIC定義的函數無法訪問類中的屬性;
- 說明:SELF與JAVA中的this關鍵字具有一樣的效果;
-
-
對比STATIC與MEMBER函數定義的區別
- 示例1:使用兩種不同的方式來定義函數
CREATE OR REPLACE TYPE emp_object AS OBJECT( atri_empno NUMBER(4) , -- 僱員編號 -- 修改當前僱員編號的工資,使用類中的empno和sal屬性 MEMBER PROCEDURE change_emp_sal_proc(p_sal NUMBER) , -- 取得當前僱員的工資 MEMBER FUNCTION get_emp_sal_fun RETURN NUMBER , -- 修改指定部門的全體僱員工資 STATIC PROCEDURE change_dept_sal_proc(p_deptno NUMBER , p_sal NUMBER) , -- 取得此部門的工資總和 STATIC FUNCTION get_dept_sal_sum_fun(p_deptno NUMBER) RETURN NUMBER ) NOT FINAL ; / |
本程序分別定義了兩組子程序,一組採用MEMBER定義,另外一組採用STATIC進行定義; |
- 接上例:定義類體實現類規範
CREATE OR REPLACE TYPE BODY emp_object AS MEMBER PROCEDURE change_emp_sal_proc(p_sal NUMBER) AS BEGIN -- 使用SELF.atri_empno找到本類中的屬性,即:更新當前對象中僱員工資 UPDATE emp SET sal=p_sal WHERE empno=SELF.atri_empno ; END ; MEMBER FUNCTION get_emp_sal_fun RETURN NUMBER AS v_sal emp.sal%TYPE ; v_comm emp.comm%TYPE ; BEGIN -- 取得當前對象中指定僱員編號的工資 SELECT sal,NVL(comm,0) INTO v_sal,v_comm FROM emp WHERE empno=SELF.atri_empno ; RETURN v_sal + v_comm ; END ; STATIC PROCEDURE change_dept_sal_proc(p_deptno NUMBER , p_sal NUMBER) AS BEGIN -- 更新指定部門全部僱員的工資 UPDATE emp SET sal=p_sal WHERE deptno=p_deptno ; END ; STATIC FUNCTION get_dept_sal_sum_fun(p_deptno NUMBER) RETURN NUMBER AS v_sum NUMBER ; BEGIN -- 查詢指定部門的工資總和 SELECT SUM(sal) INTO v_sum FROM emp WHERE deptno=p_deptno ; RETURN v_sum ; END ; END ; / |
此時類體中已經實現了類規範所定義的子程序,可以發現在MEMBER函數中可以利用"SELF.屬性"的方式取得本對象中的屬性內容(保存在類規範之中),而在STATIC函數中無法使用屬性 |
-
接上例:編寫PL/SQL塊實例化類對象
DECLARE v_emp emp_object ; BEGIN v_emp := emp_object(7369) ; -- 實例化emp_object類對象 v_emp.change_emp_sal_proc(3800) ; -- 修改7369工資 DBMS_OUTPUT.put_line('7369僱員工資:' || v_emp.get_emp_sal_fun()) ; DBMS_OUTPUT.put_line('10部門工資總和:' || emp_object.get_dept_sal_sum_fun(10)) ;-- 通過類調用 emp_object.change_dept_sal_proc(10,7000) ; -- 通過類調用 END ; / |
此時的程序分別採用了對象調用MEMBER函數並通過類調用STATIC函數的方式進行了類的功能操作。通過此時的操作可以發現,STATIC函數完全獨立類之外,並且無法通過對象進行調用 |
-
構造函數
- 說明:當創建一個類的對象時,如果希望可以自動完成某些操作,例如爲對象中的屬性賦值,可以利用構造函數;
-
定義要求:
- 構造函數的名稱必須與類名稱保持一致;
- 構造函數必須使用CONSTRUCTOR關鍵字進行定義;
- 構造函數必須定義返回值,且返回值類型必須爲SELF AS RESULT;
- 構造函數也可以進行重載,重載的構造函數參數的類型及個數不同;
- 默認的構造函數需要傳入全部屬性的值;
-
示例1:定義類規範
CREATE OR REPLACE TYPE emp_object AS OBJECT( atri_empno NUMBER(4) , -- 僱員編號 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 定義構造函數,只接收僱員編號 CONSTRUCTOR FUNCTION emp_object(p_empno NUMBER) RETURN SELF AS RESULT , -- 重載構造函數,接收僱員編號及佣金 CONSTRUCTOR FUNCTION emp_object(p_empno NUMBER , p_comm NUMBER) RETURN SELF AS RESULT ) NOT FINAL ; / |
本規範使用了CONSTRUCTOR關鍵定義了一個emp_object類的構造函數,在此構造函數中將只接受僱員編號一個參數; |
-
接上例:定義類體,實現類規範
CREATE OR REPLACE TYPE BODY emp_object AS CONSTRUCTOR FUNCTION emp_object (p_empno NUMBER) RETURN SELF AS RESULT AS BEGIN SELF.atri_empno := p_empno ; -- 保存僱員編號屬性 -- 查詢指定僱員的工資,並將其內容賦值給atri_sal屬性 SELECT sal INTO SELF.atri_sal FROM emp WHERE empno=p_empno ; RETURN ; END ; CONSTRUCTOR FUNCTION emp_object(p_empno NUMBER , p_comm NUMBER) RETURN SELF AS RESULT AS BEGIN SELF.atri_empno := p_empno ; SELF.atri_comm := p_comm ; SELF.atri_sal := 200.0 ; -- 爲atri_sal設置默認值 RETURN ; END ; END ; / |
-
接上例:使用PL/SQL塊測試構造函數
DECLARE v_emp1 emp_object ; v_emp2 emp_object ; v_emp3 emp_object ; BEGIN v_emp1 := emp_object(7369,3500) ; -- 自定義構造函數 v_emp2 := emp_object(7566) ; -- 自定義構造函數 v_emp3 := emp_object(7839,0.0) ; -- 默認構造函數 DBMS_OUTPUT.put_line('7369僱員工資:' || v_emp1.atri_sal) ; DBMS_OUTPUT.put_line('7566僱員工資:' || v_emp2.atri_sal) ; DBMS_OUTPUT.put_line('7839僱員工資:' || v_emp3.atri_sal) ; END ; / |
此程序使用了3個不同的構造函數進行對象的創建,其中一個爲默認生成的構造函數(要接收全部屬性內容),而另外兩個爲用戶自定義的構造函數(使用CONSTRUCTOR定義),在用戶自定義的構造函數中,會根據傳入的僱員編號查找此僱員的工資,並將查詢出來的結果賦值給atri_sal屬性。而另外一個構造函數會使用一個默認的數值爲atri_sal屬性賦值 |
-
定義MAP與ORDER函數
- 說明:當用戶聲明瞭多個類對象後,如果要對這些對象的信息進行排序,就不能按照NUMBER或VARCHAR2這種基本數據類型的方式進行排序了,必須專門指定比較的規則;
-
設置比較規則通過兩個函數完成:
- MAP函數:使用MAP定義的函數將會按照用戶定義的數據組合值區大小,然後利用ORDER BY子句進行排序;
- ORDER函數:ORDER函數與MAP函數類似,也是定義了一個排序規則,在進行數據排序時會默認調用。同時ORDER函數還可以比較兩個對象的大小關係,所以如果要比較多個對象時ORDER函數會被重複調用,性能不如MAP函數;
- 提示:當用戶定義一個類時,這兩種函數只能2選1;
-
示例1:在類規範中定義MAP函數
CREATE OR REPLACE TYPE emp_object_map AS OBJECT( atri_empno NUMBER(4) , -- 僱員編號 atri_ename VARCHAR2(10) , -- 僱員姓名 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 定義MAP函數,此函數會在進行排序時自動調用 MAP MEMBER FUNCTION compare RETURN NUMBER ) NOT FINAL ; / |
本類中使用MAP關鍵字定義了一個compare()函數,同時此函數返回一個數字,,該數字爲用戶自定義的一個排序規則組合 |
-
接上例:定義類體實現MAP函數
CREATE OR REPLACE TYPE BODY emp_object_map AS MAP MEMBER FUNCTION compare RETURN NUMBER AS BEGIN RETURN SELF.atri_sal + SELF.atri_comm ; END ; END ; / |
在類體中實現了compare()函數,同時在此函數中返回的是"工資+佣金"的數據組合,這樣在使用ORDER BY排序時,將採用此函數的返回值進行大小排序 |
-
接上例:編寫測試用數據庫創建腳本
-- 按照emp_object_map的結構創建一張新的數據表,這樣就可以使用MAP函數進行排序 CREATE TABLE emp_object_map_tab OF emp_object_map ; INSERT INTO emp_object_map_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7369,'SMITH',800,0) ; INSERT INTO emp_object_map_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7902,'FORD',3000,0) ; INSERT INTO emp_object_map_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7499,'ALLEN',1600,300) ; INSERT INTO emp_object_map_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7521,'WARD',1250,500) ; INSERT INTO emp_object_map_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7839,'KING',5000,0) ; COMMIT ; |
- 接上例:通過查詢實現排序
SELECT VALUE(e) ve , e.atri_empno , e.atri_ename , e.atri_sal+e.atri_comm FROM emp_object_map_tab e ORDER BY ve ; |
在本程序中,使用了一個VALUE()函數將emp_object_map_tab表中的數據取出,當利用ORDER BY 進行排序時,就會自動調用emp_object_map類中的MAP函數(compare)實現數據的組合後進行排序 |
使用MAP函數可以實現一組數據組合排序,而使用ORDER函數可以實現兩個對象間的排序 |
-
示例2:定義類規範使用ORDER定義函數
CREATE OR REPLACE TYPE emp_object_order AS OBJECT( atri_empno NUMBER(4) , -- 僱員編號 atri_ename VARCHAR2(10) , -- 僱員姓名 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 定義ORDER函數,此函數可以用於兩個對象間的比較 ORDER MEMBER FUNCTION compare(obj emp_object_order) RETURN NUMBER ) NOT FINAL ; / |
本程序將之前的MAP聲明修改爲ORDER聲明,同時在compare()函數中傳遞了一個emp_object_order的對象,這樣就可以用當前對象的數據與傳入的對象數據進行比較 |
-
接上例:定義類體實現類規範,同時實現ORDER類型函數。
CREATE OR REPLACE TYPE BODY emp_object_order AS ORDER MEMBER FUNCTION compare(obj emp_object_order) RETURN NUMBER AS BEGIN IF (SELF.atri_sal + SELF.atri_comm) > (obj.atri_sal + obj.atri_comm) THEN RETURN 1 ; ELSIF (SELF.atri_sal + SELF.atri_comm) < (obj.atri_sal + obj.atri_comm) THEN RETURN -1 ; ELSE RETURN 0 ; END IF ; END ; END ; / |
- 接上例:定義PL/SQL塊進行對象排序
DECLARE v_emp1 emp_object_order ; v_emp2 emp_object_order ; BEGIN v_emp1 := emp_object_order(7499,'ALLEN',1600,300) ; v_emp2 := emp_object_order(7521,'WARD',1250,500) ; IF v_emp1 > v_emp2 THEN DBMS_OUTPUT.put_line('7499的工資高於7521的工資。') ; ELSIF v_emp1 < v_emp2 THEN DBMS_OUTPUT.put_line('7499的工資低於7521的工資。') ; ELSE DBMS_OUTPUT.put_line('7499的工資與7521的工資相同。') ; END IF ; END ; / |
-
接上例:除了在PL/SQL中進行比較之外,也可以利用此類型創建數據表通過ORDER BY 進行排序
- 創建數據表
-- 根據emp_object_order創建數據表 CREATE TABLE emp_object_order_tab OF emp_object_order ; INSERT INTO emp_object_order_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7369,'SMITH',800,0) ; INSERT INTO emp_object_order_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7902,'FORD',3000,0) ; INSERT INTO emp_object_order_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7499,'ALLEN',1600,300) ; INSERT INTO emp_object_order_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7521,'WARD',1250,500) ; INSERT INTO emp_object_order_tab(atri_empno,atri_ename,atri_sal,atri_comm) VALUES (7839,'KING',5000,0) ; COMMIT ; |
- 進行數據查詢,同時使用ORDER BY 排序
SELECT VALUE(e) ve , e.atri_empno , e.atri_ename , e.atri_sal+e.atri_comm FROM emp_object_order_tab e ORDER BY ve ; |
-
對象嵌套關係
- 說明:利用PL/SQL的面向對象編程除了可以將基本數據類型定義爲屬性之外,還可以結合對象的引用傳遞方式,進行對象類型的嵌套;
-
示例1:定義類規範
-- 刪除emp_object DROP TYPE emp_object ; -- 定義部門類 CREATE OR REPLACE TYPE dept_object AS OBJECT ( atri_deptno NUMBER(2) , -- 部門編號 atri_dname VARCHAR2(14) , -- 部門名稱 atri_loc VARCHAR2(13) , -- 部門位置 -- 取得對象信息 MEMBER FUNCTION tostring RETURN VARCHAR2 ) NOT FINAL ; / -- 定義僱員類,每一個僱員屬於一個部門,所以設置了一個atri_dept的屬性 CREATE OR REPLACE TYPE emp_object AS OBJECT( atri_empno NUMBER(4) , -- 僱員編號 atri_ename VARCHAR2(10) , -- 僱員姓名 atri_job VARCHAR2(9) , -- 僱員職位 atri_hiredate DATE , -- 僱傭日期 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 atri_dept dept_object , -- 僱員部門 -- 取得對象信息 MEMBER FUNCTION tostring RETURN VARCHAR2 ) NOT FINAL ; / |
本程序定義了兩個類規範(dept_object,emp_object),由於每一位僱員都有一個自己的部門信息,所以在emp_object類中設置了一個dept_object類型的屬性,同時本程序在兩個類規範中都定義了tostring()函數,此函數將返回對象的基本信息 |
-
接上例:定義類體實現類規範
-- 定義dept_object類體 CREATE OR REPLACE TYPE BODY dept_object AS MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '部門編號:' || SELF.atri_deptno || ',名稱:' || SELF.atri_dname || ',位置:' || SELF.atri_loc ; END ; END ; / -- 定義emp_object類體 CREATE OR REPLACE TYPE BODY emp_object AS MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '僱員編號:' || SELF.atri_empno || ',姓名:' || SELF.atri_ename || ',職位:' || SELF.atri_job || ',僱傭日期:' || TO_CHAR(SELF.atri_hiredate,'yyyy-mm-dd') || ',工資:' || SELF.atri_sal || ',佣金:' || SELF.atri_comm ; END ; END ; / |
- 接上例:編寫PL/SQL塊驗證關係
DECLARE v_dept dept_object ; v_emp emp_object ; BEGIN -- 首先定義部門對象,此對象需要通過emp_object類的構造方法保存到v_emp對象屬性之中 v_dept := dept_object(10,'ACCOUNTING','NEW YORK') ; -- 定義僱員對象,傳遞此僱員所屬的部門對象 v_emp := emp_object(7839,'KING','PRESIDENT',TO_DATE('1981-11-11','yyyy-mm-dd'),5000,null,v_dept) ; -- 直接輸出僱員的完整信息 DBMS_OUTPUT.put_line(v_emp.tostring()) ; -- 根據信息找到其對應的部門信息 DBMS_OUTPUT.put_line(v_emp.atri_dept.tostring()) ; END ; / |
-
繼承性
- 說明:在PL/SQL中實現集成,可以利用UNDER關鍵實現
-
示例1:定義父類 —— person_object
-- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER , -- 人員編號 atri_name VARCHAR2(10) , -- 人員姓名 atri_sex VARCHAR2(10) , -- 人員性別 MEMBER FUNCTION get_person_info_fun RETURN VARCHAR2 ) NOT FINAL ; / -- 定義Person類體 CREATE OR REPLACE TYPE BODY person_object AS MEMBER FUNCTION get_person_info_fun RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex ; END ; END ; / |
-
接上例:定義子類 —— emp_object
-- 定義Emp類規範,此類爲Person子類 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) , -- 僱員職位 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 MEMBER FUNCTION get_emp_info_fun RETURN VARCHAR2 ) ; / -- 定義Emp類體 CREATE OR REPLACE TYPE BODY emp_object AS MEMBER FUNCTION get_emp_info_fun RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex || ',職位:' || SELF.atri_job || ',工資:' || SELF.atri_sal || ',佣金:' || SELF.atri_comm ; END ; END ; / |
-
接上例:利用PL/SQL程序塊測試
DECLARE v_emp emp_object ; BEGIN -- 此處必須明確寫出父類與子類的全部參數 -- person_object類需要傳入三個參數:人員編號、姓名、性別 -- emp_object類需要傳入三個參數:職位、工資、佣金 v_emp := emp_object(7369,'SMITH','FEMALE','CLERK',800.0,0.0) ; DBMS_OUTPUT.put_line('person_object類的函數:' || v_emp.get_person_info_fun()) ; DBMS_OUTPUT.put_line('emp_object類的函數:' || v_emp.get_emp_info_fun()) ; END ; / |
程序運行結果: person_object類的函數:人員編號:7369,姓名:SMITH,性別:FEMALE emp_object類的函數:人員編號:7369,姓名:SMITH,性別:FEMALE,職位:CLERK,工資:800,佣金:0 |
-
函數覆寫
- 說明:子類要覆寫父類的函數,必須在定義時,使用OVERRIDING關鍵字,定義某一個函數爲覆寫函數;
-
示例1:定義程序,實現函數的覆寫
-- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER , -- 人員編號 atri_name VARCHAR2(10) , -- 人員姓名 atri_sex VARCHAR2(10) , -- 人員性別 MEMBER FUNCTION tostring RETURN VARCHAR2 ) NOT FINAL ; / -- 定義Person類體 CREATE OR REPLACE TYPE BODY person_object AS MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex ; END ; END ; / -- 定義Emp類規範,此類爲Person子類 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) , -- 僱員職位 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 此函數名稱與父類函數名稱一樣,所以此處爲函數的覆寫 OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 ) ; / -- 定義Emp類體 CREATE OR REPLACE TYPE BODY emp_object AS OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex || '職位:' || SELF.atri_job || ',工資:' || SELF.atri_sal || ',佣金:' || SELF.atri_comm ; END ; END ; / |
此時在emp_object類中明確使用了OVERRIDING覆寫了person_object類中的tostring()函數,這樣emp_object類體中就可以繼續使用此函數名稱 |
-
接上例:編寫PL/SQL塊測試程序
DECLARE v_emp emp_object ; BEGIN -- 此處必須明確寫出父類與子類的全部參數 -- person_object類需要傳入三個參數:人員編號、姓名、性別 -- emp_object類需要傳入三個參數:職位、工資、佣金 v_emp := emp_object(7369,'SMITH','FEMALE','CLERK',800.0,0.0) ; DBMS_OUTPUT.put_line(v_emp.tostring()) ; END ; / |
-
對象多態性
-
多態體現在以下兩個方面:
- 函數的多態性:體現爲函數的重載與覆寫;
- 對象的多態性:子類對象可以爲父類對象進行實例化;
-
示例1:此示例繼續沿用筆記七的例子中的person_object和emp_object類,同時爲person_object類增加一個student_object子類;
-
在原有程序基礎上增加新的子類
-
-
-- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER , -- 人員編號 atri_name VARCHAR2(10) , -- 人員姓名 atri_sex VARCHAR2(10) , -- 人員性別 MEMBER FUNCTION tostring RETURN VARCHAR2 ) NOT FINAL ; / -- 定義Person類體 CREATE OR REPLACE TYPE BODY person_object AS MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex ; END ; END ; / -- 定義Emp類規範,此類爲Person子類 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) , -- 僱員職位 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 此函數名稱與父類函數名稱一樣,所以此處爲函數的覆寫 OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 ) ; / -- 定義Emp類體 CREATE OR REPLACE TYPE BODY emp_object AS OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex || '職位:' || SELF.atri_job || ',工資:' || SELF.atri_sal || ',佣金:' || SELF.atri_comm ; END ; END ; / -- 定義Student類規範,此類爲Person子類 CREATE OR REPLACE TYPE student_object UNDER person_object( atri_school VARCHAR2(15) , atri_score NUMBER(5,2) , OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 ) ; / -- 定義Student類體 CREATE OR REPLACE TYPE BODY student_object AS OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex || '學校:' || SELF.atri_school || ',成績:' || SELF.atri_score ; END ; END ; / |
person_object類中存在兩個子類,即emp_object和student_object,而且這兩個子類都覆寫了person_object類中的tostring()函數; |
-
通過兩個子類爲person_object類對象實例化:
DECLARE v_emp person_object ; -- 聲明person_object類對象 v_student person_object ; -- 聲明person_object類對象 BEGIN -- 對象向上轉型 v_emp := emp_object(7369,'SMITH','FEMALE','CLERK',800.0,0.0) ; v_student := student_object(7566,'ALLEN','FEMALE','MLDN',99.9) ; DBMS_OUTPUT.put_line('【僱員信息】' || v_emp.tostring()) ; DBMS_OUTPUT.put_line('【學生信息】' || v_student.tostring()) ; END ; / |
程序聲明瞭person_object類的對象(v_emp,v_student),而後這兩個對象分別通過不同的子類進行實例化,之後都可以使用父類對象進行接收,而在調用tostring()函數時執行的是不同類中覆寫之後的操作 |
-
使用FINAL關鍵字
- 說明:可以利用FINAL關鍵字定義不能被繼承的類與不能被覆寫的函數;
-
示例1:使用FINAL定義的類不能被繼承
-- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER ) FINAL ; -- 不管是否寫此句默認均爲FINAL / -- 定義Emp類規範,但是此時由於person_object類無法繼承,所以出現錯誤 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) ) ; / |
此時的程序在創建emp_object子類時會出現"PLS-00590:正在嘗試創建一個最終類型的子類型"錯誤提示消息,所以使用FINAL聲明的類不能被集成 |
-
示例2:使用FINAL定義的函數不能被子類覆寫
-- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER , FINAL MEMBER FUNCTION tostring RETURN VARCHAR2 ) NOT FINAL ; -- 不管是否寫此句默認均爲FINAL / -- 定義Emp類規範,但是此時由於person_object類無法繼承,所以出現錯誤 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) , -- 錯誤:此處無法覆寫tostring()函數 OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 ) ; / |
-
定義抽象函數
- 說明:抽象函數是指,類中的函數不希望被類對象直接使用,需要通過該類的子類來實現。在定義函數時,使用NOT INSTANTIABLE標記即可;同時,包含抽象函數所在的類也必須使用NOT INSTANTIABLE定義,這樣的類也同樣被稱爲抽象類
-
示例1:定義抽象類與抽象函數
DROP TYPE emp_object ; -- 定義Person類規範 CREATE OR REPLACE TYPE person_object AS OBJECT ( atri_pid NUMBER , -- 人員編號 atri_name VARCHAR2(10) , -- 人員姓名 atri_sex VARCHAR2(10) , -- 人員性別 NOT INSTANTIABLE MEMBER FUNCTION tostring RETURN VARCHAR2 -- 定義抽象方法 ) NOT FINAL NOT INSTANTIABLE ; -- 此處必須使用NOT INSTANTIABLE聲明類 / -- 定義Emp類規範,此類爲Person子類 CREATE OR REPLACE TYPE emp_object UNDER person_object ( atri_job VARCHAR2(9) , -- 僱員職位 atri_sal NUMBER(7,2) , -- 僱員工資 atri_comm NUMBER(7,2) , -- 僱員佣金 -- 此函數名稱與父類函數名稱一樣,所以此處爲函數的覆寫 OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 ) ; / -- 定義Emp類體 CREATE OR REPLACE TYPE BODY emp_object AS OVERRIDING MEMBER FUNCTION tostring RETURN VARCHAR2 AS BEGIN RETURN '人員編號:' || SELF.atri_pid || ',姓名:' || SELF.atri_name || ',性別:' || SELF.atri_sex || '職位:' || SELF.atri_job || ',工資:' || SELF.atri_sal || ',佣金:' || SELF.atri_comm ; END ; END ; / |
本程序在person_object類中定義了一個tostring()的抽象函數,這個函數不能直接被person_object類的對象所使用,必須由該類的子類來實現。所以在定義emp_object類時明確地使用OVERRIDING關鍵字表示要覆寫person_object類的tostring()函數 |
-
接上例:編寫程序進行測試
DECLARE v_emp person_object ; BEGIN -- 通過子類對象爲父類實例化 v_emp := emp_object(7369,'SMITH','FEMALE','CLERK',800.0,0.0) ; DBMS_OUTPUT.put_line(v_emp.tostring()) ; END ; / |