由於歷史遺留原因,很多項目也還在使用老的ABAP過程化語句進行開發,但新的SAP很多的東西都已經通過類來實現了,比如BAPI(比類還早)、BADI、ALV,還有很多東西都了已經通過類來重寫了,所以為了與時俱進,還是使用類吧
2. 面向對象
2.1. 類與接口定義
CLASS class DEFINITION [ABSTRACT][FINAL].
[PUBLIC SECTION.
[components]]
[PROTECTED SECTION.
[components]]
[PRIVATE SECTION.
[components]]
ENDCLASS.
INTERFACE intf.
[components]
ENDINTERFACE.
2.1.1. components
2 TYPES, DATA, CLASS-DATA, CONSTANTS for data types and data objects
2 METHODS, CLASS-METHODS, EVENTS, CLASS-EVENTS for methods and events
2 INTERFACES(如果在類中,表示需要實現哪個接口;如果是在接口中,表示繼承哪個接口) for implementing interfaces
2 ALIASES for alias names for interface components給接口組件取別名
2.2. 類定義、實現
CLASS math DEFINITION.
PUBLIC SECTION.
METHODS divide_1_by
IMPORTING operand TYPE i
EXPORTING result TYPE f
RAISING cx_sy_arithmetic_error.
ENDCLASS.
CLASS math IMPLEMENTATION.
METHOD divide_1_by.
result = 1 / operand.
ENDMETHOD.
ENDCLASS.
2.3. 接口定義、實現
INTERFACEint1.
ENDINTERFACE.
CLASSclass DEFINITION. [?defi?ni??n]
PUBLICSECTION.
INTERFACES: int1,int2."可實現多個接口
ENDCLASS.
CLASS class IMPLEMENTATION. [??mpl?m?n?te?-??n]
METHOD intf1~imeth1.
ENDMETHOD.
ENDCLASS.
2.4. 類、接口繼承
CLASS<subclass> DEFINITIONINHERITINGFROM<superclass>.
INTERFACE i0.
METHODS m0.
ENDINTERFACE.
INTERFACE i1.
INTERFACES i0.
"可以有相同的成員名,因為繼承過來后,成員還是具有各自的命名空間,在實現時
"被繼承過來的叫 i0~m0,在這里的名為i1~m0,所以是不同的兩個方法
METHODS m0.
METHODS m1.
ENDINTERFACE.
2.5. 向下強轉型?=
CLASS person DEFINITION.
ENDCLASS.
CLASS stud DEFINITION INHERITING FROMperson.
ENDCLASS.
START-OF-SELECTION.
DATA p TYPE REF TO person.
DATA s TYPE REF TO stud.
CREATE OBJECT s.
p = s. "向上自動轉型
"拿開注釋運行時拋異常,因為P此時指向的對象不是Student,而是Person所以能強轉的前提是P指向的是Student
"CREATE OBJECT p.
2.6. 方法
METHODS/CLASS-METHODS meth [ABSTRACT|FINAL]
[IMPORTING parameters [PREFERRED PARAMETER p]]
[EXPORTING parameters]
[CHANGING parameters]
[{RAISING|EXCEPTIONS} exc1 exc2 ...].
應該還有一個Returning選項,且RETURNING不能與EXPORTING、CHANGING同時使用:
2.6.1. parameters
... { VALUE(p1) | REFERENCE(p1) | p1 }
{ TYPE generic_type }
|{TYPE{[LINE OF] complete_type}|{REF TO {data|object|complete_type |class|intf}}}
|{LIKE{[LINE OF] dobj}|{REF TO dobj} }
[OPTIONAL|{DEFAULT def1}]
{ VALUE(p2) | REFERENCE(p2) | p2 }...
2 data、object:表示是通用數據類型data、object
2 complete_type:為完全限定類型
2 OPTIONAL與DEFAULT兩個選項不能同時使用,且對於EXPORTING類型的輸入參數不能使用
2 如果參數名p1前沒有使用VALUE、REFERENCE,則默認為還是REFERENCE,即引用傳遞
2 方法中的輸入輸出參數是否能修改,請參考Form、Function參數的傳值傳址
2.6.2. PREFERRED PARAMETER首選參數
設置多個IMPORTING類型參數中的某一個參數為首選參數。
首選參數的意義在於:當所有IMPORTING類型都為可選optional時,我們可以通過PREFERRED PARAMETER選項來指定某一個可選輸入參數為首選參數,則在以下簡單方式調用時:[CALL METHOD] meth( a ). 實參a的值就會傳遞給設置的首選參數,而其他不是首參數的可選輸入參數則留空或使用DEFAULT設置的默認值
注:此選項只能用於IMPORTING類型的參數;如果有必選的IMPORTING輸入參數,則沒有意義了
2.6.3. 普通調用
[CALL METHOD] meth|me->meth|oref->meth|super->meth|class=>meth[(]
[EXPORTING p1 = a1 p2 = a2 ...]
{ {[IMPORTING p1=a1 p2=a2 ...][CHANGING p1 = a1 p2 = a2 ...]}
|[RECEIVING r = a ] }RECEIVING不能與EXPORTING、CHANGING同時使用
[EXCEPTIONS [exc1 = n1 exc2 = n2 ...]
[OTHERS = n_others] ] [)].
如果省略CALL METHOD,則一定要加上括號形式;如果通過CALL METHOD來調用,則括號可加可不加
RECEIVING:用來接收METHODS /CLASS-METHODS 中RETURNING選項返回的值
如果EXPORTING、IMPORTING、CHANGING、RECEIVING、EXCEPTIONS、OTHERS同時出現時,應該按此順序來編寫
注:使用此種方式調用(使用 EXPORTING、IMPORTING等這些選項)時,如果原方法聲明時帶了返回值RETURNING,只能使用RECEIVING來接受,而不能使用等號來接收返回值,下面用法是錯誤的:
num2 = o1->m1( EXPORTING p1 = num1 ).
2.6.4. 簡單調用
此方式下輸入的參數都只能是IMPORTING類型的參數,如果要傳CHANGING、EXPORTING、RAISING、EXCEPTIONS類型的參數時,只能使用上面通用調用方式。
2 meth( )
此種方式僅適用於沒有輸入參數(IMPORTING)、輸入\輸出參數(CHANGING)、或者有但都是可選的、或者不是可選時但有默認值也可
2 meth( a )
此種方式僅適用於只有一個必選輸入參數(IMPORTING)(如果還有其他輸入參數,則其他都為可選,或者不是可選時但有默認值也可),或者是有多個可選輸入參數(IMPORTING)(此時沒有必選輸入參數情況下)的情況下但方法聲明時通過使用PREFERRED PARAMETER選項指定了其中某個可選參數為首選參數(首選參數即在使用meth( a )方式傳遞一個參數進行調用時,通過實參a傳遞給設置為首選的參數)
2 meth( p1 = a1 p2 = a2 ... )
此種方式適用於有多個必選的輸入參數(IMPORTING)方法的調用(其它如CHANGING、EXPORTING沒有,或者有但可選),如果輸入參數(IMPORTING)為可選,則也可以不必傳
2.6.5. 函數方法
Return唯一返回值
METHODS meth
[IMPORTING parameters [PREFERRED PARAMETER p]]
RETURNINGVALUE(r) typing
[{RAISING|EXCEPTIONS} exc1 exc2 ...].
RETURNING :用來替換EXPORTING、CHANGING,不能同時使用。定義了一個形式參數 r 來接收返回值,並且只能是值傳遞
具有唯一返回值的函數方法可以直接用在以下語句中:邏輯表達式(IF、ELSEIF、WHILE、CHECK、WAIT)、CASE、LOOP、算術表達式、賦值語句
函數方法可以采用上面簡單調用方式來調用:meth( )、meth( a )、meth( p1 = a1 P2 = a2 ... )
ref->m( RECEIVING r = i ).
CALL METHOD ref->m( RECEIVING r = i ).
CALL METHOD ref->m RECEIVING r = i.
2.7. me、super
等效於Java中的 this、super
2.8. 事件
2.8.1. 事件定義
EVENTS|CLASS-EVENTS evt [EXPORTING VALUE(p1)
{ TYPE generic_type }
|{TYPE {[LINE OF] complete_type} |
{ REF TO{data|object|complete_type|class|intf}} }
| {LIKE{[LINE OF] dobj} | {REF TO dobj} }
[OPTIONAL|{DEFAULT def1}]
VALUE(p2) ...].
2 data、object:表示是通用數據類型data、object
2 complete_type:為完全限定類型
2 OPTIONAL與DEFAULT兩個選項不能同時使用
2 EXPORTING:定義了事件的輸出參數,並且事件定義時只能有輸出參數,且只能是傳值
非靜態事件聲明中除了明確使用EXPORTING定義的輸出外,每個實例事件其實還有一個隱含的輸出參數sender,它指向了事件源對象,當使用RAISE EVENT語句觸發一個事件時,事件源的對象就會分配給這個sender引用,但是靜態事件沒有隱含參數sender
事件evt的定義也是在類或接口的定義部分進行定義的
非靜態事件只能在非靜態方法中觸發,而不能在靜態方法中觸發;而靜態事件即可在靜態也可在非靜態方法中進行觸發,或者反過來說:實例方法既可觸發靜態事件,也可觸發非靜態事件,但靜態方法就只能觸發靜態事件
2.8.2. 事件觸發
RAISE EVENT evt [EXPORTING p1 = a1 p2 = a2 ...].
該語句只能在定義evt事件的同一類或子類,或接口實現方法中進行調用
當實例事件觸發時,如果在event handler事件處理器聲明語句中指定了形式參數sender,則會自動接收事件源,但不能在RAISE EVENT …EXPORTING語句中明確指定,它會自動傳遞(如果是靜態事件,則不會傳遞sender參數)
CLASS c1 DEFINITION.
PUBLIC SECTION.
EVENTS e1 EXPORTING value(p1) TYPE string value(p2) TYPE i OPTIONAL. "定義
METHODS m1.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD m1.
RAISE EVENT e1 EXPORTING p1 = '...'."觸發
ENDMETHOD.
ENDCLASS.
2.8.3. 事件處理器Event Handler
靜態或非靜態事件處理方法都可以處理靜態或非靜態事件,與事件的靜態與否沒有直接的關系
INTERFACE window. "窗口事件接口
EVENTS: minimize EXPORTINGVALUE(status) TYPE i."最小化事件
ENDINTERFACE.
CLASS dialog_window DEFINITION. "窗口事件實現
PUBLIC SECTION.
INTERFACES window.
ENDCLASS.
INTERFACE window_handler. "窗口事件處理器接口
METHODS: minimize_window FOR EVENT window~minimize OF dialog_window
IMPORTING status sender. "事件處理器方法參數要與事件接口定義中的一致
ENDINTERFACE.
2.8.4. 注冊事件處理器
實例事件處理器(方法)注冊(注:被注冊的方法只能是用來處理非靜態事件的方法):
SET HANDLER handler1 handler2 ... FOR oref|{ALL INSTANCES}[ACTIVATION act].
靜態事件處理器(方法)注冊(注:被注冊的方法只能是用來處理靜態事件的方法):
SET HANDLER handler1 handler2 ... [ACTIVATION act].
oref:只將事件處理方法handler1 handler2注冊到 oref 這一個事件源對象
ALL INSTANCES:將事件處理方法注冊到所有的事件源實例中
ACTIVATION act:表示是注冊還是注銷
2.8.5. 示例
CLASS c1 DEFINITION."事件源
PUBLIC SECTION.
EVENTS: e1 EXPORTING value(p1) TYPE c,e2.
CLASS-EVENTS ce1 EXPORTING value(p2) TYPE i.
METHODS:trigger."事件觸發方法
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD trigger.
RAISE EVENT: e1 EXPORTING p1 = 'A',e2,ce1 EXPORTING p2 = 1.
ENDMETHOD.
ENDCLASS.
靜態(如下面的h1方法)或非靜(如下面的h2方法)態事件處理方法都可以處理靜態或非靜態事件,事件的處理方法是否只能處理靜態的還是非靜態事件與事件的靜態與否沒有關系,但事件的觸發方法與事件的靜態與否有關系(實例方法既可觸發靜態事件,也可觸發非靜態事件,但靜態方法就只能觸發靜態事件);但是,事件處理方法雖然能處理的事件與事件的靜態與否沒有關系,但如果處理的是靜態事件,那此處理方法就成為了靜態處理器,只能采用靜態注冊方式對此處理方法進行注冊。如果處理的是非靜態事件,那此處理方法就是非靜態處理器,只能采用非靜態注冊方式對此處理方法進行注冊
處理器的靜態與否與處理方法本身是否靜態沒有關系,只與處理的事件是否靜態有關
CLASS c2 DEFINITION."監聽器:即事件處理器
PUBLIC SECTION.
"靜態方法也可以處理非靜態事件,此方法屬於非靜態處理器,只能采用非靜態注冊方式
CLASS-METHODS h1 FOR EVENT e1 OF c1 IMPORTING p1 sender.
"非靜態方法處理非靜態事件,此方法屬於非靜態處理器,只能采用非靜態注冊方式
METHODS: h2 FOR EVENT e2 OF c1 IMPORTING sender,
"非靜態方法當然更可以處理靜態事件,此方法屬於靜態處理器,只能采用靜態注冊方式
h3 FOR EVENT ce1 OF c1 IMPORTING p2.
ENDCLASS.
CLASS c2 IMPLEMENTATION.
METHOD h1 .
WRITE: 'c2=>h1'.
ENDMETHOD.
METHOD: h2.
WRITE: 'c2->h2'.
ENDMETHOD.
METHOD: h3.
WRITE: 'c2->h3'.
ENDMETHOD.
ENDCLASS.
DATA: trigger TYPE REF TO c1,
trigger2 TYPE REF TO c1,
handler TYPE REF TO c2.
START-OF-SELECTION.
CREATE OBJECT trigger.
CREATE OBJECT trigger2.
CREATE OBJECT handler.
"由於h1、h2兩個處理方法分別是用來處理非靜態事件e1、e2的,所以只能采用實例注冊方式
SET HANDLER: c2=>h1 handler->h2 FOR trigger,
"h3處理方法是用來處理靜態事件ce1的,屬於靜態處理器,所以只能采用靜態注冊方式
handler->h3.
trigger->trigger( ).
"雖然trigger( )方法會觸發 e1,e2,ce1 三種事件,但h1、h2未向實例trigger2注冊,而h3屬於靜態處理器,與實例無關,即好比向所有實例注冊過了一樣
trigger2->trigger( ).