Oracle12C--操作类中的其他结构(65)

来源:互联网 发布:杭州贰贰网络 编辑:程序博客网 时间:2024/06/07 23:37
  • 定义函数
    • 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 FINALNOT 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 ;

/

原创粉丝点击