标签:不用 uil orderby 命名空间 持续时间 主程 parallel dict receive
编程语言发展史:
?
面向过程语言( Procedural Programming Model )的特点:
面向过程语言( Procedural Programming Model )的组成:
?
Encapsulation of Data Using Function Groups:
?
Multiple Instantiation in Object-Oriented Programming(多重实例化的概念):the possibility to create several runtime instances using the same program context(即可以通过一个类实现多个对象)
?
用函数组封装和用类封装的区别:
?
ABAP OO的特点:
?
Client/Server Relationship Between Objects(对象交互类似于客户/服务器模式):
?
Object-Oriented Programming的重要概念:
?
面向对象语言( Object-Oriented Programming )的特点:
面向对象语言( Object-Oriented Programming )的优点:
类( Class )的概念:
?
类( Classes )和对象( Objects )的对比:
?
UML概念:
(更多参考资料请查看http://www.omg.org)
?
UML图类:
?
类图( Class diagrams )的组成:
?
类图关联( association )有两种特别的类型:
?
时序图( sequence diagrams )展示的动作有:
时序图( sequence diagrams )展示的状态有:
?
The Delegation Principle委托原则:即类与类层层调用,不可省略中间的类
Class的定义:
?
Attributes的类型:
?
Key Characteristics of Methods方法的关键特性:
?
ZTEST26代码(注意: 因为教材中的代码零散而且不全,故以ZTEST26为例,然后按教材的知识点进行评点)
*&------------------------- | 1. 定义与实现 CLASS <name> DEFINITION. ... ENDCLASS.即类定义 CLASS <name> IMPLEMENTATION. ... ENDCLASS.即类实现 ? 2. 属性定义 DATA: 普通属性 CLASS-DATA: 静态属性 CONSTANTS: 常量属性 TYPES: 类型属性 (READ-ONLY指外部能访问但是不能修改) ? 3. 属性可见性Visibility of Attributes PUBLIC SECTION.:父类、子类、外部均可访问 PROTECTED SECTION.: 父类、子类可访问,外部不能访问 PRIVATE SECTION.: 父类可访问,子类、外部不能访问 (如果要调试私有变量,则需要借助友元函数) ? Class Interface: 公有属性( public components )之和被称为类接口 ? 若子类继承了父类的方法,但是希望重写( overwrite )旧方法,就需要在定义部分使用REDEFINITION关键字。 ? 4. 静态属性( static attributes )与实例属性( instance attributes ) CLASS-DATA: 静态属性 DATA: 实例属性 CLASS-METHODS: 静态方法 METHODS: 实例方法 (注意: 定义部分方法的关键字为METHODS、CLASS-METHODS,但是实现部分的关键字都是METHOD) ? 普通的属性和方法,在类实例化后开辟内存并存值,它们在堆内存区,需要new和free关键字用于开辟或释放内存(老版ABAP使用CREATE OBJECT开辟内存)。 ? 静态的属性和方法,在程序加载时就开辟内存并存值,它们在静态内存区(常量也在该内存区)。所以它们不需要类实例化,且具有唯一性(即同一类的实例公用一套静态属性)。 ? ABAP中也将静态属性称为class attributes,它们主要用于定义: (1) Types and constants (2) Central application data buffers (3) Administrative information, such as instance counter ? 注意:类内部调用静态方法可以省略类名,而调用实例方法需借助me指针。 ? 5. Methods Signatures方法签名: 在定义部分,方法签名如下 METHODS <method_name> [ IMPORTING iv_par TYPE <type_name> EXPORTING ev_par TYPE <type_name> CHANGING cv_par TYPE <type_name> RETURNING value( rv_par ) TYPE <type_name> EXCEPTIONS exception RAISING exception_class ]. ? IMPORTING: 输入参数 EXPORTING: 输出参数 CHANGING: 可修改参数 RETURNING: 返回值,最多一个,且不能和EXPORTING和CHANGING同时使用 EXCEPTIONS: 普通异常,不能与异常类并存 RAISING: 异常类,不能与普通异常并存 ? Functional Methods(函数方法): 只含有一个RETURNING参数,以及若干IMPORTING、EXCEPTION参数的方法。(这种方法最大的用途是隐式调用。) ? 我们可以在IMPORTING和CHANGING参数后面使用OPTIONAL和DEFAULT关键字,把它们做成可选且有默认值的输入参数。 ? 如果我们定义了EXCEPTIONS参数,那么就能像Function Modules那样配合sy-subrc获取运行结果状态。 ? 如果我们定义了RAISING参数,那么不能使用sy-subrc,而应该使用TRY. ... CATCH. ... ENDTRY.语句。 ? 6. 方法可见性Visibility of Methods(可参考属性可见性) In a class, declaration of attribute names, method names, event names, constant names, type names, and alias names share the same namespace. 一个类的方法和属性共用命名空间,故它们不能重名,只有重写( overwrite )的方法可以重名。 ? 7. 静态方法( static methods )与实例方法( instance methods )(可参考静态属性与实例属性) ? 8. UML跟Visibility的关系 +表示公有的 #表示保护的 -表示私有的 _表示静态的 ? 9. 类的内部调用静态方法可以省略类名 |
?
类的实例化代码示例:
DATA: go_vehicle1 TYPE REF TO lcl_vehicle, go_vehicle2 LIKE go_vehicle1, go_vehicle3 LIKE go_vehicle1. ? CREATE OBJECT go_vehicle1. go_vehicle2 = go_vehicle1. CREATE OBJECT go_vehicle3. ? IF go_vehicle1 IS INITIAL. ... ENDIF. ? IF go_vehicle1 IS BOUND. ... ENDIF. | 1. Reference variable: 引用,用TYPE REF TO定义,未实例化前没有指向内存区 ? 2. CREATE OBJECT: 定义对象的语句,它会开辟新的内存区;与之形成对比的是,=会让两边的引用指向同一个内存区。 ? 3. Garbage Collector: 程序运行时自动运行的例程,会将没有引用指向的内存区回收。 ? 4. IS INITIAL: 没有实例化(也可用IS NOT BOUND) IS BOUND: 已经实例化(也可用IS NOT INITIAL) (BOUND关键字为只对object reference起作用。) ? 5. object reference和data reference: 我们平时类的引用就是object reference,其实普通数据可以使用data reference,其写法如下: CREATE DATA gv TYPE string. gv->* = ‘AB‘. |
?
多实例( multiple instances )代码示例:
(1) 实例表: DATA: go_vehicle TYPE REF TO lcl_vehicle, gt_vehicle TYPE TABLE OF REF TO lcl_vehicle. ? CREATE OBJECT go_vehicle. APPEND go_vehicle TO gt_vehicles. ? CREATE OBJECT go_vehivle. APPEND go_vehicle TO gt_vehicles. | (2) 聚合( aggregation ): DATA: go_vehicle TYPE REF TO lcl_vehicle, go_wheel TYPE REF TO lcl_wheel. ? CREATE OBJECT go_vehicle. DO ... TIMES. CREATE OBJECT go_wheel. * add wheel to vehicle ... ENDDO. |
?
调用方法的代码示例:
(1) 传统写法: CALL METHOD ref->method_name EXPORTING iv_par = val_ex ... IMPORTING ev_par = val_im ... CHANGING cv_par = val_chg ... RECEIVING rv_par = val_res EXCEPTIONS exception = val_rc... . ? CALL METHOD class_name=>method_name EXPORTING iv_par = val_ex ... IMPORTING ev_par = val_im ... CHANGING cv_par = val_chg ... RECEIVING rv_par = val_res EXCEPTIONS exception = val_rc... . | (2) SAP Web AS 6.10以后的写法: ref->method_name( EXPORTING iv_par = val_ex ... IMPORTING ev_par = val_im ... CHANGING cv_par = val_chg ... RECEIVING rv_par = val_res EXCEPTIONS exception = val_rc... ). ? class_name=>method_name( EXPORTING iv_par = val_ex ... IMPORTING ev_par = val_im ... CHANGING cv_par = val_chg ... RECEIVING rv_par = val_res EXCEPTIONS exception = val_rc... ). |
?
?
函数方法( Functional Method )定义:
(1) MOVE, CASE, LOOP语句
(2) Logical expressions ( IF, WHILE, CHECK, WAIT UNTIL )
(3) Arithmetic and bit expressions ( COMPUTE )
(4) ABAP7.50的WRITE语句
?
函数方法调用代码:
(1) 传统写法: DATA gv_number TYPE i. ... CALL METHOD lcl_vehicle=>get_n_o_vehicles RECEIVING rv_count = gv_number. | (2) SAP R/3 4.6A以后的写法: result = ref->func_method_name( iv_par_1 = val_ex_1 ... Iv_par_n = val_ex_n). ? result = class_name=>func_method_name( iv_par_1 = val_ex_1 ... Iv_par_n = val_ex_n). |
?
隐式调用函数方法代码(若有EXPORTING参数则不能隐式调用):
DATA: go_veh1 TYPE REF TO lcl_vehicle, go_veh2 TYPE REF TO lcl_vehicle, gv_avg_fue1 TYPE s_consum. ... gv_avg_fue1 = go_veh1->get_average_fue1( iv_distance = 500 iv_fuel = ‘50.0‘ ) + go_veh2->get_average_fue1(iv_distance = 500 iv_fuel = ‘60.0‘ ). |
?
属性访问与方法访问的写法类似。
ABAP中Constructor(构造函数)的特点:
?
代码可以参考2.1节ZTEST26的代码。
ABAP中Static Constructor(静态构造函数)的特点:
?
当我们第一次访问一个类且将要执行以下操作时,将触发静态构造函数:
?
静态构造函数与自指针代码示例:
(1) 静态构造函数 CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. CLASS-METHODS class_constructor. METHODS constructor IMPORTING ... . PRIVATE SECTION. CLASS-DATA gv_n_o_vehicles TYPE i. ENDCLASS. ? CLASS lcl_vehicle IMPLEMENTATION. METHOD class_constructor. ... ENDMETHOD. ? METHOD constructor. ... ENDMETHOD. ENDCLASS. ? ... gv_number = lcl_vehicle=>get_n_o_vehicles( ). | (2) 自指针 CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. ... METHODS set_type IMPORTING iv_make TYPE string ... . PRIVATE SECTION. DATA: make TYPE string. ... ENDCLASS. ? CLASS lcl_vehicle IMPLEMENTATION. METHOD set_type. DATA make TYPE string. ? me->make = iv_make. TRANSLATE me->make TO UPPER CASE. ? make = me->make. CONCATENATE ‘_‘ make INTO make. ... ENDMETHOD. ENDCLASS. |
?
为什么要有继承:
?
代码知识点
代码可参考2.1节的ZTEST26。
?
?
Subclass Constructors子类构造函数: 子类构造函数的参数可以与父类不同,如下:
CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. METHODS constructor IMPORTING iv_make_v TYPE string. ENDCLASS. ? CLASS lcl_vehicle IMPLEMENTATION. METHOD constructor. mv_make = iv_make_v. ENDMETHOD. ENDCLASS. ? CLASS lcl_truck DEFINITION INHERITING FROM lcl_vehicle. PUBLIC SECTION. METHODS constructor IMPORTING iv_make_t TYPE string Iv_cargo_t TYPE s_plan_car. PRIVATE SECTION. DATA mv_cargo TYPE s_plan_car. ENDCLASS. ? CLASS lcl_truck IMPLEMENTATION. METHOD constructor. super->constructor( iv_make_v = iv_make_t ). mv_cargo = iv_cargo_t. ENDMETHOD. ENDCLASS. | 子类构造函数遵循以下原则:
? 例如: 有类lcl1,构造函数为constructor( iv_a1 : i ) lcl2继承lcl1,无构造函数 lcl3继承lcl2,构造函数为constructor( iv_a1 : i, iv_a2 : i) 那么代码将如下: ? DATA: go_2 TYPE REF TO lcl_2, go_3 TYPE REF TO lcl_3. ? CREATE OBJECT go_2 EXPORTING iv_a1 = 100. CREATE OBJECT go_3 EXPORTING iv_a1 = 100 iv_a2 = 1000. ? 可以看到构建lcl2的对象时,依然需要提供父类参数,而定义lcl3的构造函数时,需要考虑上层父类函数需要的参数。 |
?
注意:
PUBLIC SECTION、PROTECTED SECTION、PRIVATE SECTION,它们的顺序不能打乱。
(三者的定义请参考2.1节ZTEST26代码右侧第3部分说明。)
?
继承与静态( Inheritance and Static Components )几个原则:
Upcasts: 即用父类指针指向子类对象(多态就是这样实现的)
(注意: 如果子类重定义了父方法,用父指针指向子对象后,调用的其实是子类方法,即多态。)
?
Upcasts代码示例(含静态类型与动态类型的概念):
DATA: go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck. ? CREATE OBJECT go_truck. go_vehicle = go_truck. ? 注意: 对于go_vehicle而言,其静态类型为lcl_vehicle,其动态类型为lcl_truck。只有静态类型为动态类型同类或父类时,我们才能使用=直接赋值。 | 静态( Static )类型和动态( Dynamic )类型的概念:
? 在ABAP Debugger中,动态类型的格式如下: object_id<\PROGRAM = program_name\CLASS = dynamic_tuype> |
?
多态( Polymorphism )的定义: Objects from different classes react differently to the same method calls.
?
可以参考2.1节ZTEST26的代码。在这段代码里,我用一个in_aminal指针调用了不同动物的shout动作。
?
面向过程的语言实现伪多态效果( Generic Calls in the Procedural Programming Model ):
FUNCTION-POOL s_vehicle. ... FUNCTION display_truck. ... ENDFUNTION. ? FUNCTION display_bus. ... ENDFUNCTION. | DATA: gt_vehicles TYPE TABLE OF vehicle_type, gs_vehicle LIKE LINE OF vehicle_list. ... LOOP AT gt_vehicles INTO gs_vehicle. CALL FUNCTION gs_vehicle-func_name. ENDLOOP. ... | 这里的func_name字段以字符串形式保存了各个函数的名称。因为ABAP中CALL FUNCTION之后跟的就是字符串,所以这里可以直接使用。 |
?
Downcasts: 即父类指针指向了子对象之后,再用子指针指向upcasts之后的对象(就可以重新调用子对象非继承的属性和方法)
?
Downcasts代码示例:
METHOD get_max_cargo. DATA: lo_vehicle TYPE REF TO lcl_vehicle, lo_truck TYPE REF TO lcl_truck. ? LOOP AT mt_vehicles INTO lo_vehicle. TRY. lo_truck ?= lo_vehicle. CATCH cx_sy_move_cast_error. ENDTRY. ENDLOOP. ENDMETHOD. | 1. ?=符号代表downcasts,也可以写成MOVE ... ?TO ...。 ? 2. downcasts如果出错,会报出cx_sy_move_cast_error这种异常,我们可以用TRY. ... CATCH ... . ENDTRY.这种语句抓捕异常。另一种避免runtime error的方法是使用runtime type identification ( RTTI ) classes。 |
?
使用继承的优点:
使用继承的风险:
Interfaces: can be seen as superclasses that cannot be instantiated, do not contain implementations.
?
接口其实和抽象类类似,允许我们通过一个指针指向子类,然后调用子类的方法实现多态。不过接口与抽象类的区别是,接口不受继承关系的限制,一些不同源的类也可以使用同样的接口。具体代码可以参考2.1节的ZTEST26代码。
?
使用接口的步骤:
?
用本名和别名调用接口方法的区别:
INTERFACE lif_partner. METHODS display_partner. DATA gv_partner_id TYPE n LENGTH 10. ENDINTERFACE. ? CLASS lcl_rental DEFINITION. PUBLIC SECTION. INTERFACES lif_partner. ALIASES display_partner1 FOR lif_partner~display_partner. ? PRIVATE SECTION. ALIASES gv_partner_id FOR lif_partner~gv_partner_id. ENDCLASS. ? DATA go_rental TYPE REF TO lcl_rental. … CREATE OBJECT go_rental… . … go_rental->lif_partner~display_partner( ). go_rental->display_partner1( ). |
|
?
请参考2.1节ZTEST26中通过接口实现多态的方法。
Downcasts with Interfaces:
METHOD book_flight. DATA: lo_carrier TYPE REF TO lcl_carrier, lo_partner TYPE REF TO lif_partner. LOOP AT mt_partners INTO lo_partner. TRY. lo_carrier ?= lo_partner. CATCH cx_sy_move_cast_error. ENDTRY. ENDLOOP. ENDMETHOD. | 可以看到,用接口构建实例表和用父类指针构建实例表的方法其实差不多。在2.1节的ZTEST26中,我们同样构建了一个实例表。 |
?
接口允许继承关系:
?
对有继承关系的接口的实现代码示例:
INTERFACE lif_partner. METHODS display_partner. ENDINTERFACE. ? INTERFACE lif_lodging. INTERFACES lif_partner. METHODS book_room. ENDINTERFACE. ? CLASS lcl_hotel DEFINITION. PUBLIC SECTION. INTERFACES lif_lodging. ENDCLASS. ? CLASS lcl_hotel IMPLEMENTATION. METHOD lif_partner~display_partner. … ENDMETHOD. ? METHOD lif_lodging~book_room. … ENDMETHOD. ENDCLASS. |
|
?
继承接口的upcasts和downcasts代码示例:
DATA: go_hotel TYPE REF TO lcl_hotel, go_partner TYPE REF TO lif_partner, go_lodging TYPE REF TO lif_lodging. ? go_hotel->lif_partner~display_partner( ). go_hotel->lif_lodging~book_room( ). ? *Up-Casts for generic access: go_lodging = go_hotel. go_lodging->lif_partner~display_partner( ). go_lodging->book_room( ). ? go_partner = go_hotel. go_partner->display_partner(). ? *Down-Casts for specific access again: go_lodging ?= go_partner. go_hotel= ?= go_partner. |
|
?
当我们无法用继承关系描述有关的类时,使用接口有以下好处:
事件( Events )的概念:
?
事件的定义与抛出代码示例:
CLASS raising_class DEFINITION. PUBLIC SECTION. EVENTS eventname [ EXPORTING value( ev_par ) TYPE typename ]. ENDCLASS. ? CLASEE raising_class IMPLEMENTATION. METHOD methodname. RAISE EVENT eventname [ EXPORTING ev_par = lv_par ]. ENDMETHOD. ENDCLASS. |
|
?
事件的处理代码示例:
CLASS lcl_rental DEFINITION. METHODS on_vehicle_created FOR EVENT vehicle_create OF lcl_vehicle IMPORTING SENDER. ENDCLASS. ? CLASS lcl_rental IMPLEMENTATION. METHOD on_vehicle_created. ... ENDMETHOD. ENDCLASS. |
|
?
句柄的注册( registration )与注销( revoke )代码示例:
SET HANDLER ref_handler->on_eventname [ FOR ref_sender | FOR ALL INSTANCES ] [ ACTIVATION flag ] |
|
CLASS lcl_rental IMPLEMENTATION. METHOD constructor. ... SET HANDLER me->on_vehicle_created FOR ALL INSTANCES. ENDMETHOD. ENDCLASS. |
?
其它重要知识点:
?
事件( Events )的可见性( Visibilities ):
?
句柄函数( Handler Methods )的可见性( Visibilities ):
?
需要注意的是,Event-Handler的可见性只能等于其相应的Events或比该Events更加严格。
(更全的代码,可以参考TAW12-2 Unit5 Solution14。)
在接口中定义事件的方法(因为接口不实现,就不考虑抛出事件或句柄的逻辑):
(总体而言,与类的事件处理类似。参考TAW12-1 250页的代码。)
创建全局类的事务代码: SE24
通过本地类创建全局类的方法: SE24->对象类型->导入(下一节有详细过程)
?
Class Builder常用按钮:
(1) Method需要定义参数和异常,还需要编写逻辑代码( 点击Source code按钮 )
(2) Signature按钮运行用户在编写代码时查看参数与异常
(3) Goto->Method definition按钮允许用户修改属性
?
Navigation Area( SE80 ): SE80允许我们用右键创建类的组件,也可以通过Class->Print or Method->Print打印选中部分的代码。
?
Class Builder Testing Environment( SE24测试运行环境 ):
(1) Select an event
(2) Choose Handler to register a standard method for the event
(3) Call a method in which the event trigger was implemented
(4) The event that was triggered and all of the exported actual parameters are displayed in a list
?
在ABAP Editor中使用全局类的方法:
DATA: go_hotel TYPE REF TO cl_hotel. CREATE OBJECT go_hotel. CALL METHOD go_hotel->display_attributes( ). |
|
?
(Class Builder的使用详细方法请参考第三方资料。)
全局接口的创建: 与全局类类似,可以使用SE24也可以使用SE80。当我们的名称以ZIF_或YIF_开头时,系统会自动弹出创建接口的界面,而如果以其它的Z*或Y*开头时,系统则会自动弹出创建类的界面。
?
接口的实现: 在全局类的Interfaces页签,定义要使用的接口,在Methods页签可以看到接口的方法被带入了,此时双击方法名就可以编写逻辑代码。(此处有个窍门,在Utilities->Settings中有个按接口和父类分组的复选框,可以让Methods页签里的方法按照接口和父类进行分组显示。)
?
将本地类和本地接口导入Class Builder变成全局类和全局接口的方法:
在SAP NetWeaver 7.0 Enhancement Package2之后,Class Builder可以为已存在的代码创建UML。
?
Class Builder(SE24)中跟继承有关的按钮包括:
?
在全局类中定义本地类型:
(1) Local Definition/Implementations(老版为Local Class Implementations): 通过点击同名按钮进入,可以定义非私有的local interfaces、local class definitions、local types、local class implementations,甚至可以包括其它INCLUDE文件
(2) Class Relevant Local Definitions(老版为Local Types): 在定义属性时,Typing字段选择Type Ref To,输入要自定义的类型名称,然后选择右箭头按钮,系统将自动进入该INCLUDE文件并创建属性与类型的代码,用户可以对代码进行手工调整。可定义私有的local interfaces、local class definitions、local types、local class implementations,主要用于复杂的方法参数
?
类组件的显示技巧:
(1) No sort
(2) Name ( A ... Z )
(3) Name ( Z ... A )
(4) Visibility
(5) Scope ( static/instance )
ALV Grid Control: It is a tool to display non-hierarchical lists in a standardized form. It contains a number of interactive standard functions that users of lists often need ( print, export ... ).
Container Controls: They provide the technical connection between the screen and application controls ( ALV Grid Control, Tree Control, Picture Control ).
?
几种CONTAINER对比:
?
创建ALV的代码示例:
DATA: go_container TYPE REF TO cl_gui_custom_container, go_grid TYPE REF TO cl_gui_alv_grid. ? CREATE OBJECT go_container EXPORTING container_name = ‘CONTAINER_1‘. ? CREATE OBJECT go_grid EXPORTING i_parent = go_container. ? go_grid->set_table_for_first_display( i_structure_name = ‘SAPLANE‘ it_outtab = gt_saplane ). | 具体步骤如下:
? 注意:
|
?
响应ALV的代码示例(双击事件):
DATA: go_grid TYPE REF TO cl_gui_alv_grid. ? CLASS lcl_event_handler DEFINITION. PUBLIC SECTION. METHODS: on_double_click FOR EVENT double_click OF cl_gui_alv_grid IMPORTING es_row_no e_column. ... ENDCLASS. ? CLASS lcl_event_handler IMPLEMENTATION. METHOD on_double_click. ... MESSAGE i010(bc401) WITH es_row_no-row_id e_column-fieldname. ENDMETHOD. ENDCLASS. ? DATA: go_handler TYPE REF TO lcl_event_handler. CREATE OBJECT go_handler. SET HANDLER go_handler->on_double_click FOR go_grid. | 如果要响应ALV的事件,我们需要:
|
?
注意: ABAP Workbench的Enjoy Demo Center向用户提供了各种标准的DEMO(事务代码DWDM)。
BAdIs的概念: With a BAdI, an SAP application provides the enhancement option through an interfaces and an adapter class implementing that interface.
?
定义BAdI的过程:
?
The Search for BAdIs(搜索BAdI的方法):
?
附: 进入源代码的方法。首先进入一个事务代码,按F1,然后选择Technical Information按钮。找到源代码所在程序,双击程序名。然后使用global search->Edit->Find Next。注意,不能用Edit->Find/Replace( Ctrl + F ),因为后者不包括INCLUDE程序。
?
To Implement a BAdI(实施BAdI的方法):
异常类示例代码:
REPORT?ZTEST25. |
|
?
创建异常类的步骤:
有两种消息模式可选: (1) Online Text Repository ( OTR ),即直接文本; (2) Message Class,即消息类
如果选择类Message Class,则需要在SE91创建消息类,以及消息编号
如果选择OTR,则创建CHAR型文本并有一个文本ID
带参数的消息格式如下: This airplane type &planetype& is unknown,中间的字符会根据参数值变化
?
ZCX_TEST中就有三个异常文本,其中第一个异常文本总是与异常类同名。在ZTEST25的代码中,我们通过ZCX_TEST=>ZCX_TEST的方法使用了这个异常文本。
?
显式抛出异常,先创建异常类,再用RAISE EXCEPTION抛出异常类。
隐式抛出异常,直接RAISE EXCEPTION TYPE <exception_class> [ EXPORTING ... ].
?
定义与获取异常文本的代码示例:
RAISE EXCEPTION TYPE cx_invalid_planetype. | 1. 第一种方式,模式使用异常类同名的异常文本 2. 第二种方式,手动选择要用的异常文本 3. 第三种方式,使用标准的get_text()函数获取异常文本 |
RAISE EXCEPTION TYPE cx_invalid_planetype EXPORTING TEXTID = cx_invalid_planetype=>cx_invalid_planetype2. | |
DATA lx_exception TYPE REF TO cx_invalid_planetype. CATCH cx_invalid_planetype INTO lx_exception. Lv_text = lx_exception->get_text( ). |
?
抛出异常与捕获异常的代码示例:
METHODS constructor IMPORTING ... RAISING cx_exc. | RAISE EXCEPTION TYPE cx_exc EXPORTING ... . |
?
CLEANUP与CATCH在多层级时的区别:
因为CX_ROOT不能直接继承,所以我们定义的异常类都继承自三个子类:
?
CATCH之后可以使用的技术:
(1) Ignoring the exception( do nothing )( Continue program, do not propagate an exception )
(2) Issuing a warning
(3) Writing to a protocol
(4) Correcting the situation( Remove the Cause of error )
(1) RETRY ( SAP NetWeaver 7.0 EhP 2 )
(2) RESUME ( SAP NetWeaver 7.0 EhP 2 )
(1) RAISE EXCEPTION <obj_ref>.
(2) RAISE EXCEPTION TYPE <exc_class>.
?
RETRY语句示例:
主程序: DATA: go_plane TYPE REF TO lcl_airplane, gx_exc TYPE REF TO cx_exc. ? TRY. CREATE OBJECT go_plane EXPORTING ... . ? CATCH cx_exc INTO gx_exc. <remove cause of the exception> RETRY. ENDTRY. | lcl_airplane类中有关代码: METHODS constructor IMPORTING ... RAISING cx_exc. ? METHOD constructor. RAISE EXCEPTION TYPE cx_exc EXPORTING ... . ENDMETHOD. ? RETRY会在处理完异常后,再次回到TRY.语句行。 |
?
RESUME语句示例:
主程序: TRY. CREATE OBJECT go_plane EXPORING ... . ... <other statements> CATCH BEFORE UNWIND cx_exc INTO gx_exc. IF gx_exc->is_resumable = ‘X‘. RESUME. ENDIF. ... ENDTRY. ? RESUME语句,会跳到上次出错语句之后的那一句继续执行,比如示例中CREATE OBJECT出错以后会跳转到<other statements>对应的的语句。 | lcl_airplane类中有关代码: METHODS constructor IMPORTING ... RAISING RESUMABLE ( cx_exc ). ? METHOD constructor. ... CALL METHOD me->get_tech_attr EXPORTING ... IMPORTING ... . ... ENDMETHOD. ? METHODS get_tech_attr IMPORTING ... EXPORTING ... RAISING RESUMABLE ( cx_exc ). ? METHOD get_tech_attr. ... RAISE RESUMABLE EXCEPTION TYPE cx_exc EXPORTING ... . ... ENDMETHOD. |
?
RESUME语句的使用前提:
?
MAPPING传递异常类:
第一层代码: METHODS get_tech_attr IMPORTING ... EXPORTING ... RAISING ex_exc. ? METHOD get_tech_attr. ... RAISE EXCEPTION TYPE cx_exc EXPORTING ... . ENDMETHOD. | 第二层代码: METHOD constructor IMPORTING ... RAISING cx_exc2. ? METHOD constructor. ... TRY. CALL METHOD me->get_tech_attr. CATCH ex_exc INTO lx_exc. RAISE EXCEPTION TYPE cx_exc2 EXPORTING previous = lx_exc. ENDTRY. ENDMETHOD. | 第三层代码: TRY. CREATE go_plane EXPORTING ... . ... CATCH cx_exc2 INTO gx_exc. ... ENDTRY. ? 传递异常类,可以看到抛出ex_exc2时,把previous设为了ex_exc。主程序可以用previous属性进行追踪。 |
?
Re-Raise Exceptions再抛出:
第一层代码: METHODS get_tech_attr IMPORTING ... EXPORTING ... RAISING cx_exc. ? METHOD get_tech_attr. ... RAISE EXCEPTION TYPE cx_exc EXPORTING ... . ... ENDMETHOD. | 第二层代码: METHODS constructor IMPORTING ... RAISING cx_exc. ? METHOD constructor. TRY. CALL METHOD me->get_tech_attr. CATCH cx_exc INTO lx_exc. ... RAISE EXCEPTION lx_exc. ENDTRY. ENDMETHOD. | 第三层代码: TRY. CREATE OBJECT go_plane EXPORTING ... . ... CATCH cx_exc INTO gx_exc. ... ENDTRY. ? 这里我们隐式抛出了一个异常类,捕获之后又显式抛出了一个异常类。 |
?
抽象类(Abstract Class): contains both definition and implementation but cannot be instantiated.
REPORT?ZTEST34. |
|
?
最终类(Final Classes)
CLASS lcl_test DEFINITION FINAL [ INHERITING FROM ... ]. ... ENDCLASS. ? CLASS lcl_test DEFINITION. ... METHODS ... FINAL ... . ... ENDCLASS. |
|
?
内表与类对象是兼容的,代码示例:
TYPES: BEGIN OF gty_s_vehicle, make TYPE string, mode1 TYPE string, ref TYPE REF TO lcl_vehicle END OF gty_s_vehicle, gty_t_vehicle TYPE TABLE OF gty_s_vehicle. ? DATA: gs_vehicle TYPE gty_s_vehicle, gt_vehicle TYPE gty_t_vehicle. ? READ TABLE gt_vehicles INTO gs_vehicle WITH KEY make = ... mode1 = ... . CALL METHOD gs_vehicle-ref-> ... . ? LOOP AT gt_vehicles INTO gs_vehicle WHERE make = ... . ... ENDLOOP. |
?
只读的公共属性,代码示例:
CLASS lcl_vehicle DEFINITION. PUBLIC SECTION. DATA: make TYPE string READ-ONLY, mode1 TYPE string READ-ONLY. ENDCLASS. ? DATA: go_vehicle TYPE REF TO lcl_vehicle, gt_vehicles TYPE TABLE OF REF TO lcl_vehicle. ? READ TABLE gt_vehicles INTO go_vehicle WITH KEY table_line->make = ... table_line->mode1 = ... . ? LOOP AT gt_vehicle INTO go_vehicle WHERE table_line->make = ... . ... ENDLOOP. |
|
?
Navigation Methods and Chain Method Calls:
Navigation Methods: (假设lcl_vehicle是lcl_rental的组件) DATA: go_rental TYPE REF TO lcl_rental, go_vehicle TYPE REF TO lcl_vehicle. ? go_vehicle = go_rental->get_vehicle( ... ). go_vehicle->display_attributes(). |
|
Chain Method Call: DATA: go_rental TYPE REF TO lcl_rental. ? go_rental->get_vehicle( ... )->display_attributes( ). |
?
用NEW创建对象:
DATA: go_vehicle TYPE REF TO lcl_vehicle. ? CREATE OBJECT go_vehicle EXPORTING iv_make = ‘VM‘ iv_mode1 = ‘1200‘. ? go_vehicle = NEW #( iv_make = ‘VM‘ iv_mode1 = ‘1200‘ ). ? go_vehicle = NEW lcl_truck( iv_make = ‘DAIMLER‘ iv_mode1 = ‘ACTROS‘ iv_cargo = 25000 ). | DATA: gt_vehicles TYPE TABLE OF REF TO lcl_vehicle. ? APPEND NEW #( iv_make = ‘PORSCHE‘ iv_mode1 = ‘911‘ ) TO gt_vehicles. ? DATA: go_rental TYPE lcl_rental. ? go_rental->add_vehicle( io_vehicle = NEW lcl_truck( iv_make = ‘DAIMLER‘ iv_mode1 = ‘ACTROS‘ iv_cargo = 25000 ) ). ? DATA: go_alv TYPE REF TO cl_gui_alv_grid. ? go_alv = NEW # ( i_parent = NEW cl_gui_custom_container( container_name = ‘CONTAINER_1‘ ) ). |
|
?
Dynamic Type of Object Reference(AS ABAP 7.50以后增加的IS INSTANCE OF和CASE TYPE OF语句):
IS INSTANCE OF语句的用法: DATA: gt_vehicles TYPE TABLE OF REF TO lcl_vehicle, go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck. ? LOOP AT gt_vehicles INTO go_vehicle. IF go_vehicle IS INSTANCE OF lcl_truck. go_truck ?= go_vehicle. ENDIF. ENDLOOP. | CASE TYPE OF语句的用法: DATA: gt_vehicles TYPE TABLE OF REF TO lcl_vehicle, go_vehicle TYPE REF TO lcl_vehicle, go_truck TYPE REF TO lcl_truck, go_bus TYPE REF TO lcl_bus. ? LOOP AT gt_vehicles INTO go_vehicle. CASE TYPE OF go_vehicle. WHEN TYPE lcl_truck INTO go_truck. ... WHEN TYPE lcl_bus. ... WHEN OTHERS. ENDLOOP. |
?
Visibility of the Instance Constructor(实例化的可见性):
CLASS lcl_test1 DEFINITION CREATE PUBLIC. ... ENDCLASS. ? CLASS lcl_test2 DEFINITION CREATE PROTECTED. ... ENDCLASS. ? CLASS lcl_test3 DEFINITION CREATE PRIVATE. ... ENDCLASS. |
|
?
Advantages of Factory Methods(静态方法创建单件的优点):
?
Factory Method示例代码和Singleton Pattern示例代码:
CLASS lcl_airplane DEFINITION. CLASS-METHODS: factory IMPORTING ... RETURNING value( ro_plane ) ... . ENDCLASS. ? CLASS lcl_airplane IMPLEMENTATION. METHOD factory. READ TABLE gt_instances INTO ro_plane. IF sy-subrc <> 0. CREATE OBJECT ro_plane. APPEND ro_plane TO gt_instances. ENDIF. ENDMETHOD. ENDCLASS. | CLASS lcl_singleton DEFINITION. CLASS-METHODS: get_instance ... RETURNING value( ro_plane ). ENDCLASS. ? CLASS lcl_singleton IMPLEMENTATION. METHOD get_instance. IF go_instance IS BOUND. ro_instance = go_instance. ELSE. CREATE OBJECT go_instance. ro_instance = go_instance. ENDIF. ENDMETHOD. ENDCLASS. |
?
Using the Static Constructor用静态构造函数创建单件:
CLASS lcl_singleton DEFINITION. CLASS-METHODS: class_constructor, get_instance IMPORTING ... RETURNING value( ro_instance ). ENDCLASS. ? CLASS lcl_singleton IMPLEMENTATION. METHOD class_constructor. CREATE OBJECT go_instance. ENDMETHOD. ? METHOD get_instance. ro_instance = go_instance. ENDMETHOD. ENDCLASS. |
|
?
Friendship Relationships友元关系:
类1: CLASS lcl_1 DEFINITION CREATE PRIVATE FRIENDS lcl_2. ... PRIVATE SECTION. DATA a1 ... . ... ENDCLASS. | 类2: CLASS lcl_2 DEFINITION. ... ENDCLASS. ? CLASS lcl_2 IMPLEMENTATION. ... METHOD meth. DATA lo_1 TYPE REF TO lcl_1. CREATE OBJECT lo_1. MOVE lo_1->a1 TO .... ENDMETHOD. ... ENDCLASS. |
|
?
普通的ABAP程序数据与对象只在runtime有效,程序结束就会消失。如果想要数据和对象在程序结束后不消失,就需要可持续对象。
?
创建持久类的方法:
?
Creation of Persistent Objects创建可持续对象:
DATA: go_carrier TYPE REF TO zcl_carrier, go_agent TYPE REF TO zca_carrier. ? go_agent = zca_carrier=>agent. ? TRY. go_carrier = go_agent->create_persistent( i_carrid = ‘LH‘ i_carrname = ‘Lufthansa‘ ). ? CATCH cx_os_object_existing. ... ENDTRY. ? go_carrier->... ."You may save the data to transparent table COMMIT WORK. |
|
?
Access to Persistent Objects访问可持续对象:
DATA: go_carrier TYPE REF TO zcl_carrier, go_agent TYPE REF TO zca_carrier, gv_carrname TYPE s_carrname. ... go_agent = zca_carrier=>agent. TRY. go_carrier = go_agent->get_persistent( i_carrid = ‘LH‘ ). gv_carrname = go_carrier->get_carrname(). WRITE: ‘LH: ‘, gv_carrname. CATCH cx_os_object_not_found. ... ENDTRY. |
|
?
OO Transaction面向对象的事务代码:在transaction maintenance(SE93)中,我们可以创建面向对象的事务代码。这种事务代码可以通过ABAP Objects Services和持久类对象关联,也可以直接和全局类的公有实例方法、本地类的公有实例方法进行关联。当我们调用事务代码时,系统将在internal session创建实例,并调用实例方法。
?
如果我们勾选了OO Transaction Model,则系统将事务代码和ABAP Objects Service事务代码服务(即持久类)连接。否则,我们可以直接连接全局类或本地类的实例方法。
?
与全局类连接时,该全局类不能有屏幕定义:
?
创建OO Transaction的步骤:
?
事务代码的数据表为TSTC。
同步调用特点:
?
SUBMIT同步调用代码示例:
SUBMIT prog_name_2. | 跳转到prog_name_2,返回时回到调用时的界面(比如在ABAP Editor运行调用程序,最后就返回(BACK) ABAP Editor界面) |
SUBMIT prog_name_2 AND RETURN. | 跳转到prog_name_2,返回(BACK)时回到SUBMIT语句下一句继续执行 (注意: 回到主调程序界面而不是Editor界面,并继续执行) |
SUBMIT prog_name_2 VIA SELECTION-SCREEN AND RETURN. | 跳转到prog_name_2的选择屏,返回(BACK)时回到SUBMIT语句下一句继续执行 |
DATA set {TYPE|LIKE} RANGE OF {type|dataobject}. ? SUBMIT prog_name AND RETURN [ VIA SELECTION-SCREEN ] WITH parameter {EQ|NE|...} val WITH sel_opt {EQ|NE|...} val SIGN {‘I‘|‘E‘} WITH sel_opt BETWEEN val1 AND val2 SIGN {‘I‘|‘E‘} WITH sel_opt BETWEEN val1 AND val2 SING {‘I‘|‘E‘} WITH sel_opt IN set. ? MODULE user_command_0200 INPUT. CASE save_ok. WHEN ‘CTRYFR‘. SUBMIT sapbc402_tabd_hashed WITH pa_ctry = sdyn_conn-countryfr AND RETURN. ENDCASE. ENDMODULE. | 完整的SUBMIT写法见左侧,这种方式的优点就是支持select-options的使用。 |
?
TRANSACTION同步调用代码示例:
LEAVE TO TRANSACTION ‘T_CODE‘ [AND SKIP FIRST SCREEN]. | LEAVE TO这种方式与在command field输入/NT_CODE效果相同,都是终止当前程序进入被调用程序,返回(LEAVE PROGRAM)时回到调用界面 |
CALL TRANSACTION ‘T_CODE‘ [AND SKIP FIRST SCREEN]. | CALL方式,暂停当前程序进入被调用程序,返回(LEAVE PROGRAM)时回到CALL语句下一语句继续执行 AND SKIP FIRST SCREEN允许跳过第一个界面(一般为输入界面) 我们可以用UPDATE关键字选定更新数据的方式,默认为asynchronous,但也可以选择synchronous或local |
DATA: gt_bdcdata TYPE TABLE OF bdcdata, gs_bdcdata TYPE bdcdata. ? * fill gt_bdcdata ... ? * call other program CALL TRANSACTION ‘T_CODE‘ USING gt_bdcdata. IF sy-subrc = 0. ... ELSE. ... ENDIF. ? CALL TRANSACTION ‘T_CODE‘ USING gt_bdcdata MODE ‘N‘. IF sy-subrc <> 0. MESSAGE ... WITH sy-subrc. ENDIF. | BDCDATA: BDC数据,包括要调用的程序、要输入的参数等 ? MODE: 在CALL TRANSACTION之后,确定屏幕显示方式
? MESSAGE INTO: 在CALL TRANSACTION之后,可存放系统消息到内表中,该内表必须包含BDCMSGCOLL的结构。 ? SY-SUBRC可以判断调用是否成功。 ? 用内表传输数据的优点:
|
?
BDCDATA结构:
program | dynpro | dynbegin | fnam | fval |
SAPBC402_CALD_CREATE_CUSTOMER | 0100 | X | ? | ? |
? | ? | ? | SCUSTOM-NAME | <current_name> |
? | ? | ? | SCUSTOM-CITY | <current_city> |
? | ? | ? | BDC_OKCODE | SAVE |
program: 长度40字符,存放程序名,只能在BDCDATA第一排 dynpro: 长度4字符,存放屏幕编号,只能在BDCDATA第一排 dynbegin: 长度1字符,第一行标识,第一行为X,其它行为空 fnam: 长度132字符,字段名称,N/A即非数字 fval: 长度132字符,字段值,大小写敏感 |
?
LOAD的定义: when you generatea development, the system creates a runtime object, or LOAD. ( 菜单栏Program->Generate )即运行进程时的程序对象( 只针对Program )。
?
The system generates the LOAD automatically in the following situations:
?
A saved or buffered LOAD is considered obsolete under either of the following conditions:
?
激活object的步骤:
?
程序的可修改部分与不可修改部分:
(1) Byte code for statements
(2) Values of constants and literals
(3) Program texts
(4) Screen definitions
(1) Data objects ( variables )
?
SAP Memory对应一个User Session和若干External Sessions(即窗口),每个ABAP Memory对应一个External Session和若干Internal Sessions(即程序):
?
每个Internal Session包含多个Program Groups:
?
Call Stack的作用:
?
同一个program group的程序,要遵循以下限制:
?
不同的program groups的程序,或者不同的Internal Sessions或External Sessions的程序,它们不能直接共享数据,而是需要数据交换:
?
ABAP memory读写代码示例:
PROGRAM p1 ... . DATA: gs_spfli TYPE spfli, gt_fli TYPE STANDARD TABLE OF sflight. ? EXPORT conn = gs_spfli fights = gt_fli TO MEMORY ID ‘MY_ID‘. ? PROGRAM p2 ... . DATA: gs_conn TYPE spfli gt_data TYPE STANDARD TABLE OF sflight. ? IMPORT conn = gs_conn flights = gt_data FROM MEMORY ID ‘MY_ID‘. ? FREE MEMORY ID ‘MY_ID‘. |
|
?
SAP memory读写代码示例:
PROGRAM p1 ... . SELECTION-SCREEN BEGIN OF LINE. SELECT-OPTIONS: s_gjahr FOR bkpf-gjahr MEMORY ID GJR. SELECTION-SCREEN END OF LINE. ? PROGRAM p2 ... . SET PARAMETER ID ‘GJR‘ FIELD sy-datum+0(4). CALL TRANSACTION ‘BC402_TABD_SORT‘. ? PROGRAM p3 ... . GET PARAMETER ID ‘GJR‘ FIELD lv_gjahr. |
|
?
扁平数据( Flat Data Objects ): elementary data objects with fixed length and structures that only have flat components.
扁平数据开辟内存的方式: 直接开辟内存
扁平数据释放内存的方式: 遇到CLEAR或FREE时清空内存区,只有等到internal session结束时才释放内存区
?
字符串( Strings ): 就是字符串,字符串属于深度数据对象( deep data objects ),也属于动态数据对象( dynamic data objects )
字符串开辟内存的方式: 先开辟8字节的引用,再开辟大约100字节的Header(与硬件有关),最后开辟可扩展的Data区(String可用内存区最大为2GB,用ztta/max_memreq_MB配置)
字符串释放内存的方式: 遇到CLEAR或FREE时清空Data区,但保留引用区和Header区
?
内表( Internal Table ): 与字符串类似,属于深度数据对象和动态数据对象
内表开辟内存的方法: 先开辟8字节引用,再开辟Header区,内表的Header区比较大,因为内表数据分布于不同的Data区,而Header区会存放这些Data区的地址(初次开辟内存时,可以用INITIAL SIZE指定内存大小)
内表释放内存的方法: 遇到CLEAR和REFRESH会只清空Data区,遇到FREE会清空Data区和Header区
?
Memory Optimization when Copying Dynamic Data Objects(动态数据赋值的内存优化):
DATA: gv_string1 TYPE string, gv_string2 TYPE string. ? gv_string1 = ‘abcdef‘. gv_string2 = gv_string1. CONCATENATE gv_string1 ‘ghi‘ INTO gv_string1. | 当gv_string1给gv_string2赋值时,因为值相等,它们的引用会指向同一个内存区(共享Header区),以节省内存。 当gv_string1的值不再与gv_string2的值相等时,则会开辟新内存区存放gv_string2的值。 |
DATA: gt_itab0 TYPE TABLE OF ... . gt_itab1 LIKE gt_itab0. ? SELECT * FROM ... INTO TABLE gt_itab0 WHERE ... . gt_itab1 = gt_itab0. APPEND ... TO gt_itab0. | 当gt_itab0给gt_itab1赋值时,因为值相等,它们的引用会指向同一个内存区(但分别有自己的Header区),以节省内存。 当内表数据不再一致时,则开辟新内存区存放gt_itab1的值。 |
?
SHARED BUFFER和SHARED MEMORY使用代码示例:
DATA: matnr TYPE matnr. matnr = ‘ 000000000000123456‘. EXPORT matnr TO SHARED BUFFER indx(aa) ID ‘YTEST_MATNR‘. ? IMPORT matnr FROM SHARED BUFFER indx(aa) ID ‘YTEST_MATNR‘. | 1. Shared Memory(共享内存): is a memory area on an application server that the ABAP programs running on the same server can access.(在Shared Objects诞生前,ABAP使用的就是SHARED BUFFER和SHARED MEMORY,同一个服务器的程序可以共享数据。) 2. 共享对象只有服务器关闭时才会清空,也可用FREE SHARED BUFFER这样的命令强制清空。 |
?
哪些情况适合使用Shared Objects:
?
创建共享对象( shared objects )的过程:
?
使用共享对象( shared objects )的代码示例:
REPORT?ztest38. |
|
?
ABAP支持以下类型动态编程:
?
常用的动态编程技术包括:
Dynamic Tokens in ABAP Statements(动态ABAP声明的参数代码对比):
静态 | 动态 |
DO 5 TIMES. ... ENDDO. | gv_int = 5. DO gv_int TIMES. ... ENDDO. |
WRITE gv_string+2(5). | gv_len = 5. gv_off = 2. WRITE gv_string+gv_off(gv_len). |
MESSAGE e038(BC402). MESSAGE ID ‘BC402‘ TYPE ‘E‘ NUMBER ‘038‘. | gv_msgid = ‘BC402‘. gv_msgty = ‘E‘. gv_msgno = ‘038‘. MESSAGE ID gv_msgid TYPE gv_msgty NUMBER gv_msgno. |
SORT gt_spfli TY cityfrom. | gv_comp = ‘CITYFROM‘. SORT gt_spfli BY (gv_comp). |
READ TABLE gt_spfli INTO gs_spfli WITH KEY carrid = ‘LH‘ Connid = ‘0400‘. | gv_nam1 = ‘CARRID‘. gv_val1 = ‘LH‘. gv_name2 = ‘CONNID‘. gv_val2 = ‘0400‘. READ TABLE gt_spfli INTO gs_spfli WITH KEY (gv_nam1) = (gv_val1) (gv_nam2) = (gv_val2). |
可能报错: 如果超过字符串长度,会报DATA_OFFSET_LENGTH_TOO_LARGE runtime错误 或CX_SY_RANGE_OUT_OF_BOUNDS异常类 |
?
Dynamic Open SQL(动态OPEN SQL示例):
动态FROM | gv_tabname = ‘SPFLI‘. SELECT COUNT(*) FROM (gv_tabname) INTO gv_int. |
动态FIELDS | gv_fieldlist = ‘CARRID CONNID CITYFROM CITYTO‘. SELECT (gv_fieldlist) FROM spfli INTO CORRESPONDING FIELDS OF TABLE gt_spfli. |
动态WHERE(单条) | gv_cond = ‘CARRID = ‘LH‘ AND CONNID = ‘0400‘ ‘. SELECT * FROM spfli INTO TABLE gt_spfli WHERE (gv_cond). |
动态WHERE(多条) | APPEND ‘CARRID = ‘LH‘ AND ‘ TO gt_cond. APPEND ‘CONNID > ‘0400‘ ‘ TO gt_cond. SELECT * FROM spfli INTO TABLE gt_spfli WHERE (gv_cond). |
完整展示 | REPORT?ZTEST32. |
可能报错: CX_SY_DYNAMIC_OSQL_SEMANTICS, CX_SY_DYNAMIC_OSQL_SYNTAX |
?
Dynamic Calls(动态调用代码):
调用子例程 | PERFORM (gv_form_name) IN PROGRAM (gv_prog_name). | |
调用FM | CALL FUNCTION gv_func_name … . | |
调用方法 | CALL METHOD go_instance->(gv_meth_name) … . CALL METHOD (gv_class_name)=>(gv_static_meth_name) … . | |
执行程序 | SUBMIT (gv_report_name). | |
调用事务代码 | CALL TRANSACTION gv_transaction_code … . LEAVE TO TRANSACTION gv_transaction_code … . | |
用参数表调用FM | TYPE-POOLS: abap. DATA: gt_param TYPE abap_func_parmbind_tab, gt_excp TYPE abap_func_excepbind_tab. gv_func_name = ‘Z_MY_FUNCTION‘. *fill the gt_param and gt_excep … CALL FUNCTION gv_func_name PARAMETER-TABLE gt_parm EXCEPTION-TABLE gt_excp. IF sy-subrc <> 0. … ENDIF. | ABAP_FUNC_PARMBIND_TAB有三个字段:
|
用参数表调用方法 | TYPE-POOLS: abap. DATA: gt_parm TYPE abap_parmbind_tab, gt_excp TYPE abap_excpbind_tab. gv_method_name = ‘MY_METHOD‘. *fill the gt_parm and gt_excp … CALL METHOD ref->(gv_method_name) PARAMETER-TABLE gt_parm EXCEPTION-TABLE gt_excp. | 与参数表调用FM存在区别:
|
用参数表调用程序 | DATA: gt_sel TYPE TABLE OF rsparams. gv_prog_name = ‘MY_REPORT‘. *fill gt_sel … SUBMIT (gv_prog_name) WITH SELECTION-TABLE gt_sel. | RSPARAMS包含以下字段:
|
可能报错: CX_SY_DYN_CALL_ERROR或其它CX_SY_DYN_CALL_开头的异常类(前者的子类) |
?
Persistent Program Generation(动态生成程序):
DATA gt_tab TYPE TABLE OF string. DATA gv_prg TYPE program. ? *fill internal table APPEND ‘REPORT ztest.‘ TO gt_tab. APPEND ‘PARAMETERS pa TYPE s_carr_id.‘ TO gt_tab. APPEND ‘START-OF-SELECTION.‘ TO gt_tab. APPEND ‘WRITE ‘‘Hello‘‘.‘ TO gt_tab. ? gv_prg = ‘ZTEST‘. INSERT REPORT gv_prg FROM gt_tab. ? SUBMIT (gv_prg) VIA SELECTION-SCREEN AND RETURN. | DATA gt_tab TYPE TABLE OF string. DATA gv_prg TYPE program. ? *fill internal table APPEND ‘REPORT ztest.‘ TO gt_tab. APPEND ‘FORM show.‘ TO gt_tab. APPEND ‘WRITE ‘‘Hello‘‘.‘ TO gt_tab. APPEND ‘ENDFORM.‘ TO gt_tab. ? *create S type report GENERATE SUBROUTINE POOL gt_tab NAME gv_prg. ? PERFORM show IN PROGRAM (gv_prg) IF FOUND. |
?
ABAP Built-In Generic Data Types(ABAP预定义通用数据类型):
? | Generic Data Type | Meaning | Compatible ABAP Types |
Fully gneric | any | Any type | Any |
data | Any data type | Any | |
Elementary, flat | simple | Elementary data type or flat, character-like structure | Any elementary type and any flat, character-like structure |
Numeric | numeric | Numeric data type | i, f, p, int8, decfloat16, decfloat34 |
decfloat | Decimal floating point | decfloat16, decfloat34 | |
Character-type | clike | Character data type | c, n, d, t, string |
csequence | Text data type | c, string | |
Hexadecimal | xsequence | Byte data type | x, xstring |
?
Typing for reference variables(引用通用类型):
TYPE REF TO OBJECT | Reference variables |
TYPE REF TO DATA | Reference variables |
?
Generic ABAP Data Types – Internal Tables(内表通用类型):
Generic Data Type | Meaning | Compatible ABAP Types |
any table | Any internal table | Any table type |
index table | Any index table | Standard or sorted |
standard table | Any standard table | Only standard |
sorted table | Any sorted table | Only sorted |
hashed table | Any hashed table | Only hashed |
代码示例: TYPES: gty_t_gen1 TYPE ANY TABLE OF spfli, "ANY TABLE不指定key gty_t_gen2 TYPE SORTED TABLE OF spfli WITH KEY carrid connid. "SORTED TABLE可指定unique-key或ono-unique key gty_t_gen3 TYPE INDEX TABLE OF spfli WITH DEFAULT KEY. "SORTED TABLE或STANDARD TABLE可用默认key |
?
动态参数的错误写法与正确写法对比:
CLASS-METHODS write_any_table IMPORTING ig_info TYPE ANY it_data TYPE ANY. ? METHOD write_any_table. FIELD-SYMBOLS <ls_line> TYPE ANY. "Syntax error,因为ANY不能确定是否为表 LOOP AT it_data ASSIGNING <ls_line>. … ENDLOOP. "Possible runtime error,因为ANY不能确定是否能WRITE WRITE / ig_info. ENDMETHOD. | CLASS-METHODS write_any_table IMPORTING ig_info TYPE SIMPLE it_data TYPE ANY TABLE. ? METHOD write_any_table. FIELD-SYMBOLS <ls_line> TYPE ANY. "正确,ANY TABLE必然为表 LOOP AT it_data ASSIGNING <ls_line>. … ENDLOOP. "正确,SIMPLE类型必然可以WRITE WRITE / ig_info. ENDMETHOD. |
?
Generically Typed Field Symbols(通用指针类型):????????Type Casting With Field Symbols(通过指针进行类型转换):
DATA: gt_scarr TYPE TABLE OF scar, gt_sbook TYPE TABLE OF sbook. ? FIELD-SYMBOLS: <fs_tab> TYPE ANY TABLE. "可指向任意类型内表 ? CASE gv_table_name. WHEN ‘SCARR‘. ASSIGN gt_scarr TO <fs_tab>. WHEN ‘SBOOK‘. ASSIGN gt_sbook TO <fs_tab>. ENDCASE. ? IF <fs_tab> IS ASSIGNED. SELECT * FROM (gv_table_name) UP TO 100 ROWS INTO TABLE <fs_tab>. ENDIF. | TYPES: BEGIN OF gty_s_date, year TYPE n LENGTH 4, month TYPE n LENGTH 2, day TYPE n LENGTH 2, END OF gty_s_date. *option1: implicit隐式,指明fs类型,不指明casting类型 FIELD-SYMBOLS <fs> TYPE gty_s_date. ASSIGN sy-datum TO <fs> CASTING. WRITE: / <fs>-year, <fs>-month, <fs>-day. ? *option2: explicit显式,不指明fs类型,指明casting类型 FIELD-SYMBOLS: <fs> TYPE ANY. ASSIGN sy-datum TO <fs> CASTING TYPE gty_s_date. |
?
Dynamic Access to Data Objects(用指针访问不同类型变量):
Any data object | gv_name = ‘GV_CARRID‘. ASSIGN (gv_name) TO <fs>. |
Structure component ( full name ) | gv_name = ‘LS_SPFLI-CARRID‘. "即可以不用COMPONENT获取字段 ASSIGN (gv_name) TO <fs>. |
Structure component ( component name ) | gv_comp_name = ‘CARRID‘. ASSIGN COMPONENT gv_comp_name OF STRUCTURE gs_spfli TO <fs>. |
Structure component ( position ) | gv_comp_number = 2. ASSIGN COMPONENT gv_comp_number OF STRUCTURE gs_spfli TO <fs>. |
Static attribute ( full name ) | gv_name = ‘LCL_VEHICLE=>N_O_AIRPLANES‘. ASSIGN (gv_name) TO <fs>. |
Static attribute ( part name ) | gv_attribute_name = ‘N_O_AIRPLANES‘. ASSIGN (gv_class_name)=>(gv_attribute_name) TO <fs>. |
Instance attribute ( full name ) | gv_name = ‘LO_VEHICLE->N_O_AIRPLANES‘. ASSIGN (gv_name) TO <fs>. |
Instance attribute ( part name ) | gv_attribute_name = ‘MAKE‘. ASSIGN go_vehicle->(gv_attribute_name) TO <fs>. |
?
Full Processing of Any Non-Nested, Flat Structure(处理非嵌套结构的完整代码示例):
CLASS-METHODS: write_any_struct IMPORTING is_struct TYPE any. ? METHOD write_any_struct. FIELD-SYMBOLS: <ls_comp> TYPE simple. DO. ASSIGN COMPONENT sy-index OF STRUCTURE is_struct TO <ls_comp>. "可以用index也可以用name IF sy-subrc <> 0. EXIT. ELSE. WRITE <ls_comp>. ENDIF. ENDMETHOD. |
?
Cast Assignment for Data References(数据引用的类型转换):
DATA: gv_int TYPE i VALUE 15, gv_date TYPE d VALUE ‘20040101‘. ? DATA: gr_int TYPE REF TO i, gr_date TYPE REF TO d, gr_gen TYPE REF TO data. ? GET REFERENCE OF gv_int INTO gr_int. *up cast gr_gen = gr_int. *down cast gr_int ?= gr_gen. ? *runtime error: GET REFERENCE OF gv_date INTO gr_date. *up cast gr_gen = gr_date. *down cast gr_int ?= gr_gen. |
|
?
Defreferenced Generic Data References(解引用):
DATA gr_data TYPE REF TO DATA. ... "Fill the generic data reference ASSIGN gr_data->* TO <fs>. |
|
?
在RTTI ( runtime type identification )诞生前,ABAP描述数据的关键字有DESCRIBE FIELD和DESCRIBE TABLE。
?
Only six of the ten RTTI classes can be instantiated and used to describe specific types(只有六种可实例化的RTTI类):
RTTI Class | Purpose |
CL_ABAP_ELEMDESCR | To describe elementary data types |
CL_ABAP_REFDESCR | To describe reference types |
CL_ABAP_STRUCTDESCR | To describe structure types |
CL_ABAP_TABLEDESCR | To describe table types |
CL_ABAP_CLASSDESCR | To describe classes |
CL_ABAP_INTFDESCR | To describe interfaces |
其实还有四种虚类作为上述类的超类,它们不能实例化但是可以定义引用类型,具体继承关系请看TAW12-1 590页。
?
获取类型的属性:
通过Name获取类型属性 | DATA go_type TYPE REF TO cl_abap_typedescr. ? *Analysis of a local data type TYPES gty_type TYPE ... . go_type = cl_abap_typedescr=>describe_by_name( ‘GTY_TYPE‘ ). ? *Analysis of a global data type go_type = cl_abap_typedescr=>describe_by_name( ‘SPFLI‘ ). ? *Analysis of a local object type CLASS lcl_class DEFINITION. ... ENDCLASS. go_type = cl_abap_typedescr=>describe_by_name( ‘LCL_CLASS‘ ). ? *Analysis of a global object type go_type = cl_abap_typedescr=>describe_by_name( ‘IF_PARTNERS‘ ). |
通过引用或者对象获取类型属性 | *Analysis of a generic parameter … IMPORTING ig_data_object TYPE any … go_type = cl_abap_typedescr=>describe_by_data( ig_data_object ). ? *Analysis of a reference variable ( object reference ) DATA: go_vehicle TYPE REF TO lcl_vehicle. go_type = cl_abap_typedescr=>describe_by_data( go_vehicle )."获取引用的类型参数 go_type = cl_abap_typedescr=>describe_by_object_ref( go_vehicle )."获取引用指向的对象的类型参数 |
注意:获取类型属性的方法
|
?
Casting a Suitable Reference for a Type Description Object(通过描述对象进行引用类型转换):
DATA: go_type TYPE REF TO cl_abap_trypedescr, go_elem TYPE REF TO cl_abap_elemdescr, go_ref TYPE REF TO cl_abap_refdescr, go_struct TYPE REF TO cl_abap_structdescr, go_table TYPE REF TO cl_abap_tabledescr, go_intf TYPE REF TO cl_abap_intfdescr, go_class TYPE REF TO cl_abap_classdescr. ? go_type = cl_abap_typedescr=>describe_by_ … . ? CASE go_type->kind. WHEN cl_abap_typedescr=>kind_elem. go_elem ? = go_type. WHEN cl_abap_typedescr=>kind_ref. go_ref ?= go_type. WHEN cl_abap_typedescr=>kind_struct. go_struct ?= go_type. WHEN cl_abap_typedescr=>kind_table. go_table ?= go_type. WHEN cl_abap_typedescr=>kind_intf. go_intf ?= go_type. WHEN cl_abap_typedescr=>kind_class. go_class ?= go_type. ENDCASE. |
?
Elementary Data Type Analysis(基本类型数据的类型属性分析):
DATA: gv_class TYPE sbook-class, go_elem TYPE REF TO cl_abap_elemdescr, go_dfies TYPE dfies. "该结构有单个字段的全部属性 ? go_elem ?= cl_abap_typedescr=>describe_by_data( gv_class ). ? IF go_elem->is_ddic_type( ) = cl_abap_typedescr=>true. gs_dfies = go_elem->get_ddic_field( EXPORTING p_langu = sy-langu "有些字段描述跟语言有关,就需要设置语言 ). ENDIF. |
?
Reference Type Analysis(引用型数据的类型属性分析):
DATA: gr_spfli TYPE REF TO spfli, go_ref TYPE REF TO cl_abap_refdescr, go_target TYPE REF TO cl_abap_typedescr, go_struct TYPE REF TO cl_abap_structdescr. ? go_ref ?= cl_abap_typedescr=>describe_by_data( gr_spfli )."获取引用的属性 ? "获取static type即引用定义的类型,如果为structure引用,那么返回的值即CL_ABAP_STRUCTDESCR对象,如果为class或interface引用,那么返回的值为CL_ABAP_CLASSDESCR或CL_ABAP_INTFDESCR对象 go_target = go_ref->get_referenced_type( ). ? IF go_target->kind = cl_abap_typedescr=>kind_struct. go_struct ?= go_target. ENDIF. |
?
Structure Type Analysis(结构数据的类型属性分析):
DATA: gs_spfli TYPE spfli, go_struct TYPE REF TO cl_abap_structdescr, gs_comp TYPE abap_componentdescr. "字段描述器 ? go_struct ?= cl_abap_typedescr=>describe_by_data( ls_spfli ). ? "如果我们要一次性不循环取出所有字段的属性,应该使用GET_DDIC_FIELD_LIST取出列表 "如果只取一个字段的属性,应该使用GET_DDIC_FIELD取出一个结构 LOOP AT go_struct->components INTO gs_comp. WRITE: / gs_comp-name, gs_comp-type_kind, gs_comp-length, gs_comp-deimals. ENDLOOP. |
?
Navigation from Structure Type to Component Types(通过结构去做字段的类型属性分析):
*Type description of a specific component DATA: go_struct TYPE REF TO cl_abap_structdescr, go_comp TYPE REF TO cl_abap_datadescr. ? *fill go_struct with reference to structure type go_comp = go_struct->get_component_type(‘CARRID‘ ). |
*Type description of all components DATA: go_struct TYPE REF TO cl_abap_structdescr, go_elem TYPE REF TO cl_abap_elemdescr, gt_comp TYPE cl_abap_structdescr=>component_table, gs_comp TYPE cl_abap_structdescr=>component. ? *fill go_struct with reference to structure type gt_comp = go_struct->get_components( ). LOOP AT gt_comp INTO gs_comp. IF gs_comp-type->kind = cl_abap_typedescr=>kind_elem. go_elem ?= gs_comp-type. ENDIF. ENDLOOP. ? "注意: 考虑到components的类型各种各样,我们可以用REF TO CL_ABAP_DATADESCR的引用获取components的类型属性,再通过downcast转换成REF TO CL_ABAP_ELEMDESCR这样的子类型。 |
?
Table Type Analysis(表数据的类型属性分析):
DATA: gt_spfli TYPE spfli_tab, go_table TYPE REF TO cl_abap_tabledescr, go_line TYPE REF TO cl_abap_datadescr,"我们用该类型存放每行的类型属性 go_struct TYPE REF TO cl_abap_structdescr. ? go_table ?= cl_abap_typedescr=>describe_by_data( gt_spfli ). go_line = go_table->get_table_line_type( ). "获取每行的类型属性 IF go_line->kind = cl_abap_typedescr=>kind_struct. go_struct ?= go_line. ENDIF. |
?
Object Type Analysis(对象数据的类型属性分析):
DATA: go_class TYPE REF TO cl_abap_classdescr,"有时也用cl_abap_intfdescr gs_methdescr TYPE abap_methdescr, gs_parmdescr TYPE abap_parmdescr. ? go_class ?= cl_abap_typedescr=>describe_by_name( ‘CL_RENTAL‘ ). ? "除了methods,还有attributes、events、interfaces等属性,它们都是内表 "class_kind属性允许我们查看是否为abstract、final等类型,而cl_abap_intfdescr则对应的是intf_kind属性 READ TABLE go_class->methods INTO gs_metdescr WITH KEY name = ‘CONSTRUCTOR‘. ? LOOP AT gs_metdescr-parameters INTO gs_parmdescr. WRITE: / gs_parmdescr-name, gs_parmdescr-type_kind, gs_parmdescr-length. ENDLOOP. ? "注意:GET_ATTRIBUTE_TYPE提供属性描述,GET_METHOD_PARAMTER_TYPE提供参数描述,GET_SUPER_CLASS_TYPE提供父类描述 |
?
动态的类、内表和SQL语言:
DATA: gv_tabname TYPE string, gv_max_rows TYPE i, gr_table TYPE REF TO data. ? FIELD-SYMBOLS: <gt_table> TYPE ANY TABLE. ? gv_tabname = ‘SPFLI‘. gv_max_rows = 100. ? CREATE DATA gr_table TYPE TABLE OF (gv_tabname). ? ASSIGN gr_table->* TO <gt_table>. ? SELECT * FROM (gv_tabname) UP TO gv_max_rows ROWS INTO TABLE <gt_table>. |
?
用HANDLE关键字通过descriptor创建引用对象:
DATA: gv_tabname TYPE string, gv_max_rows TYPE i, go_struct TYPE REF TO cl_abap_structdescr, go_table TYPE REF TO cl_abap_tabledescr, gr_table TYPE REF TO data. ? FIELD-SYMBOLS: <gt_table> TYPE ANY TABLE. gv_tabname = ‘SPFLI‘. gv_max_rows = 100. go_struct ?= cl_abap_typedescr=>describe_by_name( p_name = gv_tabname ). go_table = cl_abap_tabledescr=>create( "创建内表型descriptor对象 p_line_type = go_stuct ). ? CREATE DATA gr_table TYPE HANDLE go_table. "用descriptor对象创建数据引用对象 ASSIGN gr_table->* TO <gt_table>. ? SELECT * FROM (gv_tabname) UP TO gv_max_rows ROWS INTO TABLE <gt_table>. |
标签:不用 uil orderby 命名空间 持续时间 主程 parallel dict receive
原文地址:https://www.cnblogs.com/Intercalaryland/p/10522539.html