Oracle12C--操作類中的其他結構(65)

  • 定義函數
    • PL/SQL定義的類中,函數的定義有兩種方式;
      • MEMBER型函數:該函數需要通過對象進行定義,使用MEMBER定義的函數可以利用SELF關鍵字訪問類中的屬性內容;
      • STATIC型函數:該函數獨立於類之外,可以直接通過類名稱進行調用,使用STATIC定義的函數無法訪問類中的屬性;
      • 說明:SELFJAVA中的this關鍵字具有一樣的效果;
  • 對比STATICMEMBER函數定義的區別
    • 示例1:使用兩種不同的方式來定義函數

CREATE OR REPLACE TYPE emp_object AS OBJECT(

atri_empno NUMBER(4) , -- 僱員編號

-- 修改當前僱員編號的工資,使用類中的empnosal屬性

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屬性賦值

  • 定義MAPORDER函數
    • 說明:當用戶聲明瞭多個類對象後,如果要對這些對象的信息進行排序,就不能按照NUMBERVARCHAR2這種基本數據類型的方式進行排序了,必須專門指定比較的規則;
    • 設置比較規則通過兩個函數完成:
      • MAP函數:使用MAP定義的函數將會按照用戶定義的數據組合值區大小,然後利用ORDER BY子句進行排序;
      • ORDER函數:ORDER函數與MAP函數類似,也是定義了一個排序規則,在進行數據排序時會默認調用。同時ORDER函數還可以比較兩個對象的大小關係,所以如果要比較多個對象時ORDER函數會被重複調用,性能不如MAP函數;
      • 提示:當用戶定義一個類時,這兩種函數只能21
    • 示例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_objectstudent_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 ;

/

發佈了201 篇原創文章 · 獲贊 62 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章