ABAP技术总结

2019年11月05日 阅读数:1990
这篇文章主要向大家介绍ABAP技术总结,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

 

 

 

 

 

 

 

 

 

 

 

 

 

SAPhtml

——ABAP/4 技术总结 V3.0java

 

 

2014-10-14node

 

--江正军git

 

 

 

 

 

1.      基础... 1算法

1.1.           基本数据类型... 1sql

1.1.1.        P类型(压缩型)数据... 1数据库

1.2.           TYPELIKE. 2express

1.3.           DESCRIBE. 3编程

1.4.           字符串表达式... 3api

1.5.           Data elementDomain. 4

1.6.           词典预约义类型与ABAP类型映射... 5

1.7.           字符串处理... 7

1.7.1.        countmatch结合... 7

1.7.2.        FIND …SUBMATCHES. 8

1.7.3.        FIND …RESULTS  itab. 8

1.7.4.        正则式类... 9

1.7.4.1.             matchesmatch. 9

1.7.4.2.             contains. 10

1.7.4.3.             find_all10

1.7.4.4.             find_next. 11

1.7.4.5.             get_lengthget_offsetget_submatch. 11

1.7.4.6.             replace_all12

1.8.           CLEARREFRESHFREE. 12

1.9.           ABAP程序中的局部与全局变量... 12

1.10.         FormFunction. 13

1.10.1.     FORM.. 13

1.10.2.     FUNCTION.. 15

1.10.2.1.           Function Group结构... 15

1.10.2.2.           Function参数传值、传址... 18

1.11.         字段符号FIELD-SYMBOLS. 20

1.11.1.     ASSIGN隐式强转... 21

1.11.2.     ASSIGN显示强转... 21

1.11.3.     ASSIGN 动态分配... 21

1.11.4.     UNASSIGNCLEAR. 21

1.12.         数据引用、对象引用... 21

1.12.1.     数据引用Data References. 21

1.12.2.     对象引用Object references. 22

1.12.3.     GET REFERENCE OF获取变量/对象/常量地址... 22

1.13.         动态语句... 22

1.13.1.     内表动态访问... 22

1.13.2.     动态类型... 23

1.13.3.     动态SQL. 23

1.13.4.     动态调用类的方法... 23

1.13.5.     ASSIGN 动态分配... 23

1.13.5.1.           动态访问类的属性成员... 24

1.14.         反射... 24

1.14.1.     TYPE HANDLE. 24

1.14.2.     动态建立数据Data或对象Object. 25

1.14.3.     动态建立基本类型变量、结构、内表... 25

1.14.4.     类对象反射... 26

2.      面向对象... 27

2.1.           类与接口定义... 27

2.1.1.        components. 27

2.2.           类定义、实现... 27

2.3.           接口定义、实现... 27

2.4.           类、接口继承... 28

2.5.           向下强转型 ?=. 28

2.6.           方法... 28

2.6.1.        parameters. 29

2.6.2.        PREFERRED PARAMETER首选参数... 29

2.6.3.        普通调用... 29

2.6.4.        简单调用... 30

2.6.5.        函数方法... 30

2.7.           mesuper. 30

2.8.           事件... 30

2.8.1.        事件定义... 30

2.8.2.        事件触发... 31

2.8.3.        事件处理器Event Handler. 31

2.8.4.        注册事件处理器... 32

2.8.5.        示例... 32

3.      内表... 33

3.1.           LOOP AT循环内表... 33

3.1.1.        SUM.. 34

3.1.2.        AT...ENDAT. 34

3.1.3.        自已实现AT...ENDAT. 37

3.2.           LOOP AT中修改当前内表行... 39

3.2.1.        循环中修改索引表... 39

3.2.2.        循环中修改HASH... 40

3.3.           第二索引... 40

3.3.1.        使用第二索引... 41

3.3.2.        示例... 41

3.4.           适合全部类型的内表操做... 42

3.5.           适合索引内表操做... 43

4.      OPEN SQL. 43

4.1.           SELECT INSERTUPDATEDELETEMODIFY. 43

4.2.           条件操做符... 44

4.3.           RANG条件内表... 44

4.4.           FOR ALL ENTRIES. 45

4.5.           INNER JOINLEFT OUTER JOIN使用限制... 46

4.6.           动态SQL. 46

4.7.           子查询... 47

4.7.1.        =<><<=>>=子查询... 47

4.7.1.1.             ALLANYSOME. 48

4.7.2.        [NOT] IN子查询... 48

4.7.3.        [NOT] EXISTS子查询... 48

4.7.4.        相关子查询... 48

4.8.           统计函数... 48

4.9.           分组过滤... 48

4.10.         游标... 49

4.11.         三种缓存... 49

4.12.         Native SQL. 50

4.12.1.     查询... 50

4.12.2.     存储过程... 50

4.12.3.     游标... 50

4.13.         SAP... 51

5.      SAP/DB LUW.. 51

5.1.           DB LUW.. 51

5.1.1.        显式提交... 52

5.1.2.        隐式提交... 52

5.1.3.        显示回滚... 52

5.1.4.        隐式回滚... 52

5.2.           SAP LUW.. 53

5.2.1.        SAP LUW的绑定方式... 54

5.2.1.1.             Function. 54

5.2.1.2.             subroutine. 55

5.2.2.        开启新的SAP LUW.. 55

5.2.3.        同步或异步更新(提交)... 55

5.2.4.        本地、非本地方式提交... 55

6.      逻辑数据库... 56

6.1.           组成... 56

6.2.           结构... 56

6.3.           选择屏幕(Selections... 57

6.3.1.        PARAMETERS屏幕参数扩充... 58

6.3.2.        SELECTION-SCREEN格式化屏幕... 58

6.3.3.        DYNAMIC SELECTIONS动态选择条件... 58

6.3.3.1.             DYN_SEL. 60

6.3.3.1.1.          RSDS_TYPE-CLAUSES. 60

6.3.3.1.2.          RSDS_TYPE-TRANGE. 61

6.3.4.        FIELD SELECTION动态选择字段... 62

6.3.4.1.             SELECT_FIELDS. 63

6.4.           数据库程序中重要FORM.. 65

6.5.           LDB选择屏幕:静()态选择屏幕、动态选择视图... 66

7.      ALV. 70

7.1.           Layout重要字段... 70

7.2.           FIELDCATALOG重要字段... 70

7.3.           指定双击触发的FunCode. 71

7.4.           相关函数... 71

7.5.           重要参数接口... 71

7.6.           让预置按钮回调I_CALLBACK_USER_COMMAND.. 72

7.7.           颜色... 72

7.8.           可编辑... 72

7.9.           单元格数据修改后当即自动刷新... 73

7.10.         数据有效性验证事件:data_changed. 73

7.11.         金额、数字类型输入问题... 74

7.12.         排序、分类汇总... 74

7.13.         可打印的表头输出... 75

7.14.         布局变式读取、切换、根据布局格式导出数据... 75

7.15.         动态内表... 76

8.      OO ALV. 77

8.1.           相关类... 77

8.2.           控制区域、容器、Grid关系... 77

8.3.           CL_GUI_ALV_GRID重要方法... 77

8.4.           set_table_for_first_dispaly()方法重要参数... 77

8.5.           事件绑定、触发、回调处理... 77

8.6.           CL_GUI_DOCKING_CONTAINER容器... 78

8.7.           覆盖(拦截)预设按钮的功能FunCodeBEFORE_USER_COMMAND.. 78

8.8.           数据改变事件data_changeddata_changed_finished. 79

8.9.           单元格可编辑... 79

9.      问题... 79

9.1.           ALV自带导出文件时字段数据末尾被截断问题... 79

9.2.           Smartform Template没法显示减号后面内容... 80

9.3.           Smartform金额或者数量字段显示不出来... 80

9.4.           更新数据库表时,工做区或内表的结构需参考数据库表来定义... 80

9.5.           DELETE ADJACENT DUPLICATES…去重复... 80

9.6.           Text使用Excel打开乱码问题... 80

9.7.           VBFAEKPO联合查询问题... 81

10.             技巧... 81

10.1.         READ TABLE...WITH KEY可以使用OR条件或其余非“=”操做符... 81

10.2.         SELECT SINGLE ... WHERE...没法排序问题... 82

10.3.         小心Where后的条件内表为空时... 82

10.4.         快速查找SO所对应的交货单DNPO.. 82

10.5.         X类型的C类型视图... 82

10.6.         字符串链接:&& 替代 CONCATENATE. 83

10.7.         Variant变式中动态日期... 83

11.             优化... 84

11.1.         数据库... 84

11.2.         程序... 86

12.             屏幕... 88

12.1.         AT SELECTION-SCREENPAIAT USER-COMMAND触发时机... 88

12.2.         SELECTION-SCREEN格式化屏幕、激活预设按钮... 88

12.3.         PARAMETERS. 88

12.4.         SELECT-OPTIONS. 89

12.4.1.     输入ABAP程序默认值时,须要加上“=”. 89

12.4.2.     选择条件内表多条件组合规则... 89

12.4.3.     使用SELECT-OPTIONS替代PARAMETERS. 90

12.5.         各类屏幕元素演示... 91

12.6.         按钮、单选复选框、下拉框的FunCode. 91

12.6.1.     选择屏幕中的按钮... 92

12.6.2.     选择屏幕中的单选/复选按钮:点击时显示、隐藏其余屏幕元素... 92

12.6.3.     选择屏幕中下拉列表:AS LISTBOX. 93

12.7.         屏幕流逻辑... 93

12.7.1.     FIELD.. 93

12.7.2.     MODULE. 94

12.7.3.     ON INPUTON CHAIN-INPUT区别... 94

12.8.         EXIT-COMMAND.. 95

12.8.1.     MODULE <mod> AT EXIT-COMMAND.. 95

12.8.2.     AT SELECTION-SCREEN ON EXIT-COMMAND.. 95

12.9.         OK_CODE. 95

12.9.1.     ok_code使用前需拷贝... 95

12.10.       Search help F4... 95

12.10.1.            VALUE CHECKfixed ValuesValue Table. 95

12.10.2.            检查表Check Table --- Value Table. 96

12.10.3.            SE11检查表与搜索帮助关系... 96

12.10.4.            F4搜索帮助联动的决定因素... 98

12.11.       搜索帮助参数说明... 100

12.12.       F4IF_SHLP_EXIT_EXAMPLE帮助出口... 102

12.12.1.            修改数据源... 102

12.12.2.            删除重复... 103

12.13.       搜索帮助优先级... 103

12.14.       搜索帮助建立函数... 103

12.15.       POV事件里读取屏幕字段中的值函数... 104

12.16.       动态修改屏幕... 104

12.17.       子屏幕... 105

12.18.       屏幕跳转... 106

12.18.1.            CALL SCREEN误用... 106

12.18.2.            CALL SCREEN/SET SCREEN/LEAVE TO SCREEN区别... 107

12.19.       修改标准选择屏幕的GUI Status. 107

12.20.       事件分类... 107

12.20.1.            报表事件... 107

12.20.2.            选择屏幕事件... 107

12.20.3.            逻辑数据库事件... 108

12.20.4.            列表事件... 108

12.20.5.            事件流图... 109

12.21.       事件终止... 110

12.21.1.            RETURN.. 110

12.21.2.            STOP. 110

12.21.3.            EXIT. 110

12.21.4.            CHECK. 110

12.21.5.            LEAVE. 111

12.21.5.1.         REJECT. 111

13.             列表屏幕... 111

13.1.         标准LIST. 112

13.2.         自定义LIST. 112

13.3.         LIST事件... 113

13.4.         Detail Lists 建立... 113

13.5.         标准的 List Status. 113

13.6.         列表屏幕上的数据与程序间的传递... 114

13.6.1.     SY-LISEL. 114

13.6.2.     HIDE. 114

13.6.3.     READ LINE. 114

13.7.         Screen Processing 屏幕处理切换到Lists列表输出... 115

13.8.         LIST 打印输出... 115

14.             Messages. 115

14.1.         00消息ID中的通用消息... 115

14.2.         消息常量... 116

14.3.         静态指定... 116

14.4.         动态指定... 116

14.5.         消息拼接MESSAGE …INTO.. 116

14.6.         修改消息显示性为…DISPLAY LIKE….. 116

14.7.         RAISING <exc>:消息以异常形式抛出... 116

14.8.         CALL FUNCTION…EXCEPTIONS. 117

14.8.1.     error_message = n_error捕获消息... 118

14.9.         各类消息的显示及处理... 118

14.10.       异常处理... 119

14.10.1.            RAISE [EXCEPTION]…触发异常... 119

14.10.1.1.         触发类异常... 119

14.10.1.2.         RESUMABLE选项... 120

14.10.2.            捕获异常... 121

14.10.2.1.         类异常捕获TRY…CATCH.. 121

14.10.2.2.         老式方式捕获runtime errors(运行时异常)121

14.10.3.            向上抛出异常... 121

14.10.4.            类异常... 122

15.             数据格式化、转换... 123

15.1.         数据输入输出转换... 123

15.1.1.     输出时自动转换... 123

15.1.2.     输入时自动转换... 124

15.1.3.     经过转换规则输入输出函数手动转换... 124

15.2.         数量小位数格式化... 125

15.2.1.     案例... 126

15.3.         单位换算:UNIT_CONVERSION_SIMPLE. 128

15.4.         货币格式化... 129

15.4.1.     从表中读取日元并正确的格式化输出... 130

15.4.2.     SAP 货币转换因子... 131

15.4.3.     货币内外格式转换... 133

16.             业务... 134

16.1.         表、业务流程... 134

16.2.         MM.. 138

16.2.1.     经常使用表... 138

16.2.2.     库存... 139

16.2.3.     物料凭证... 139

16.3.         SD.. 139

16.3.1.     ... 139

16.3.2.     订价过程... 141

16.3.2.1.           条件技术七要素... 141

16.3.2.2.           条件表V/03V/04V/05. 142

16.3.2.3.           存取顺序 V/07. 142

16.3.2.4.           条件类型 V/06. 142

16.3.2.5.           订价过程V/08与肯定OVKK. 143

16.3.2.6.           VK11:价格主数据维护... 146

16.3.2.7.           订价计算:KONV. 147

16.3.2.7.1.       条件类型的计算公式... 147

16.3.2.8.           订价过程示例... 148

16.3.2.9.           销售订单中的订价示例... 148

16.3.2.10.         订价通讯表KOMKKOMP. 151

16.3.3.     销售相关的凭证类型、类型... 151

16.4.         业务概念... 154

16.4.1.     售达方、送达方、开票方、付款方... 154

16.4.2.     进项税、销项税... 154

16.4.3.     订单日期、凭证日期、过帐日期... 155

16.5.         业务知识... 155

16.5.1.     客户联系人相关信息... 155

16.5.2.     销售订单合做伙伴功能... 156

17.             加强... 157

17.1.         第一代:基于源码加强(子过程subroutine... 157

17.2.         第二代:基于函数出口加强(Function... 157

17.2.1.     示例:采购订单屏幕加强... 159

17.2.1.1.           定义全局变量... 161

17.2.1.2.           子屏幕... 161

17.2.1.3.           屏幕与业务表数据间传递... 162

17.2.1.4.           相关函数说明... 163

17.2.2.     如何快速找到加强... 163

17.3.         第三代:基于类的加强(BADI... 165

17.3.1.     新式BADI建立... 166

17.3.1.1.           定义... 166

17.3.1.2.           实现... 168

17.3.1.3.           过滤器... 170

17.3.1.3.1.       调用... 171

17.3.1.4.           多个BADI/ Enhancement实现时究竟调谁... 172

17.3.2.     经典BADI建立... 173

17.3.2.1.           Filter-Depend.过滤器... 174

17.3.2.1.1.       调用... 175

17.3.2.2.           经过经典BADI扩展自定义程序(菜单、屏幕、功能)... 176

17.3.3.     示例:经过BADI实现采购订单屏幕加强... 179

17.4.         第四代:Enhancement-Point. 179

17.4.1.     为本身程序建立显示加强... 180

17.4.2.     隐式与显示加强... 182

18.             数据批量维护... 182

18.1.         BDCSM35SHDB... 182

18.2.         LSMW.. 184

18.3.         业务对象和BAPI184

18.3.1.     SAP业务对象(SWO1... 184

18.3.1.1.           业务对象类型的组成... 185

18.3.1.2.           业务对象(BO)设计... 185

18.3.1.2.1.       建立业务表... 185

18.3.1.2.2.       建立业务对象类型... 186

18.3.1.2.3.       添加(继承)接口... 186

18.3.1.2.4.       添加关键字段Key. 187

18.3.1.2.5.       添加属性... 187

18.3.1.2.6.       经过报表程序来实现业务对象的方法... 189

18.3.1.2.6.1.    报表程序... 189

18.3.1.2.6.2.    重定义接口与方法实现... 190

18.3.1.2.6.3.    测试... 191

18.3.1.2.7.       经过BAPI函数来实现业务对象方法... 192

18.3.1.2.7.1.    建立BAPI参数结构... 192

18.3.1.2.7.2.    建立BAPI函数、BAPI调用返回RETURN结果处理... 193

18.3.1.2.7.3.    BAPI函数绑定到相应的业务方法... 195

18.3.2.     BAPI197

18.3.2.1.           BAPI浏览器... 197

18.3.2.2.           SE37查找:BAPI函数的命名规则... 198

18.3.2.3.           查找某事务码所对应的BAPI198

18.3.2.4.           经常使用BAPI函数... 199

18.3.2.5.           调用BAPI199

18.3.2.5.1.       BAPI事务处理... 200

18.3.2.5.2.       外部系统(Java)调用BAPI函数... 201

18.3.2.5.2.1.    直连、链接池... 201

18.3.2.5.2.2.    访问结构... 202

18.3.2.5.2.3.    访问表 (Table)203

18.3.2.5.2.4.    Java多线程调用有/无状态RFM.. 204

18.3.2.5.3.       ABAP访问Java服务... 204

18.3.2.5.4.       ABAP建立远程目标... 204

18.3.2.5.5.       链接异常registrationnot allowed. 205

18.3.2.5.6.       带状态访问... 206

18.4.         IDoc. 206

18.4.1.     数据段类型和数据段定义(WE31... 206

18.4.2.     IDoc定义(WE30... 207

18.4.3.     自定义IDoc发送与接收实例... 208

18.4.3.1.           发送端800outbound)配置... 208

1、建立segmentWE31... 208

2、建立IDOC TypeWE30... 209

3、建立Message TypeWE81... 210

4、关联Message TypeIDOC TypeWE82... 210

5、建立接收端RFC DestinationSM59... 210

6、建立到收端的端口(WE21... 211

7、建立发送端Logical System并分配(SALE... 211

8、建立接收端Logical SystemSALE... 212

9、建立接收端合做和伴配置文件Partner profileWE20... 212

10、经过ABAP程序发送IDOC. 213

18.4.3.2.           接收端810Inbound)配置... 216

1、建立发送端RFC DestinationSM59... 216

2、建立发送端的端口(WE21... 217

3、将接收端Logical System分配到Client 810SALE... 217

4、建立入站处理函数... 218

5、注册入站处理函数(BD51... 219

6、将入站函数与IDOC Type/Message Type关联(WE57... 219

7、建立入站处理代码Inbound Process CodeWE42... 219

8、建立发送端合做和伴配置文件Partner profileWE20... 219

9、测试 BD87. 220

19.             数据共享与传递... 222

19.1.         程序调用、会话、SAP/ABAP内存 关系... 222

19.2.         ABAP Memory数据共享... 224

19.2.1.     EXPORT. 224

19.2.2.     IMPORT. 226

19.2.3.     DELETE. 227

19.3.         SAP MEMORY数据共享... 228

19.3.1.     PARAMETERS/SELECT-OPTIONS选项MEMORY ID.. 228

19.3.2.     GET/SET PARAMETER ID.. 228

19.4.         DATABASE. 229

19.4.1.     将文件存入表中... 230

19.4.2.     从表中读取文件... 232

19.5.         JOB间数据传递... 233

20.             拾遗... 233

20.1.         Function调用... 233

20.1.1.     更新FMLUW.. 233

20.1.2.     RFC函数:远程调用... 234

20.1.2.1.           同步... 234

20.1.2.2.           异步... 234

20.1.2.2.1.       事务性RFC调用... 234

20.1.2.3.           DESTINATION 取值... 234

20.2.         函数、类... 235

20.3.         FTP. 235

20.4.         文件读写... 235

20.5.         Email236

20.6.         XML. 236

20.6.1.     生成... 237

20.6.2.     解析... 240

20.7.         OLE. 242

20.7.1.     导出Exel文件多种方式... 243

20.8.         ABAP示例代码... 244

20.9.         长文本... 244

20.9.1.     物料长文本... 244

20.9.2.     生产定单长文本... 245

20.9.3.     采购定单长文本... 246

20.9.4.     销售定单长文本... 246

20.10.       Smart Forms. 246

20.11.       BOM.. 247

20.12.       传输请求SE01SE09SE10. 247

20.13.       Script Form传输:SCC1. 247

20.14.       权限检查... 247

20.15.       容许对表数据维护... 248

20.16.       SE93建立事务码... 248

20.17.       表字段初始值、NULL等问题... 249

20.17.1.            SE11表设置中的Initial Values. 249

20.17.2.            底层数据库表字段默认值... 249

20.17.3.            ABAP初始值、底层数据库表默认值相互转换... 250

20.17.3.1.         向表中插入初始值... 250

20.17.3.2.         读取数据... 251

20.17.4.            SAP系统中的表字段不容许为NULL的缘由... 251

20.18.       ABAP中的“空”、INITIAL. 251

20.19.       调试工具... 252

20.19.1.            ST05. 252

20.20.       程序建立Job(报表自已设置后台运行,先后台数据共享)... 253

20.21.       SE78SWM0. 254

20.22.       客户端文本文件或Excel文件上传与下载... 255

20.22.1.            读取客户端TxtExcel文件到内表:TEXT_CONVERT_XLS_TO_SAP. 255

20.22.2.            将数据内表导出为EXCEL文件:SAP_CONVERT_TO_XLS_FORMAT. 256

20.23.       Unicode字符串互转... 256

20.24.       字符编码与解码... 256

20.25.       ABAP中的特殊字符列表... 257

20.26.       下载文件... 257

20.26.1.            BIN二进制下载... 257

20.26.2.            以字符模式下载... 258

20.27.       将文件上传到数据库表中,并可邮件发送... 259

20.28.       AppendInclude系统表结构加强... 261

20.29.       结构复用(INCLUDE... 262

20.30.       经常使用事务码... 263

21.             经常使用Function. 265

21.1.         日期函数... 265

21.1.1.     日期、时间验证... 265

21.1.2.     内部转换外部格式... 265

21.1.3.     外部转内部格式... 266

21.1.4.     获取Client格式... 267

21.1.5.     日期加减... 267

21.1.6.     转成工厂日期... 267

21.1.7.     日期属性... 269

21.1.8.     节假日... 270

21.1.9.     年月选择框... 271

21.1.10.            财政年... 271

21.1.11.            星期翻译对照表... 271

21.1.12.            日期所在周末、天/周、周/... 272

 

 

1.   基础

1.1.  基本数据类型

CNDTIFPXstringXstring

P默认为8字节,最大容许16字节。最大整数位:16*2 = 32 - 1 = 31 -14(容许最大小数位数) = 17位整数位

类型

最大长度(字符数)

默认长度

说明

C

1~262143个字符

1 字符

 

N

1~262143个字符

1 字符

09之间字符组成的数字字符串

D

8 个字符

 

日期格式必须为 YYYYMMDD

T

6 个字符

 

格式为 24-hour HHMMSS

I

4 bytes

 

-2.147.483.648 to +2.147.483.647

F

8 bytes

 

小数位最大能够到17位,便可精确到小数点后17

P

1 to 16 bytes

8 bytes

两个数字位压缩后才占一个字节,因为0-9的数字只须要4Bit位,因此一个字节实质上容许存储二位数字,这就是P数据类型为压缩数据类型的由来。并借用半个字节来存储小数点位置、正号、负号相关信息

X

1~524,287 bytes

1 byte

十六进制字符 0-9, A-F具体的范围为:00~FF

类型X是十六进制类型,可表示内存字节实际内容,使用两个十六制字符表示一个字节中所存储的内容。但直接打印输出时,输出的仍是赋值时字面意义上的值,而不是Unicode解码后的字符

若是未在 DATA 语句中指定参数<length>,则建立长度为 1

注:若是值是字母,则必定要大写

1.1.1.P类型(压缩型)数据

是一种压缩的定点数,其数据对象占据内存字节数和数值范围取定义时指定的整个数据大小和小数点后位数,若是不指定小数位,则将视为I类型。其有效数字位大小能够是从1~31位数字(小数点与正负号占用一个位置,半个字节),小数点后最多容许14个数字

P类型的数据,可用于精确运算(这里的精确指的是存储中所存储的数据与定义时字面上所看到的大小相同,而不存在精度丢失问题——看到的就是内存中实实在在的大小)。在使用P类型时,要先选择程序属性中的选项 Fixed point arithmetic(即定点算法,通常默认选中),不然系统将P类型看用整型。其效率低于IF类型。

"16 * 2 = 32表示了整个字面意义上容许的最大字面个数,而14表示的是字面上小数点后面容许的最大小数位,而不是指14个字节,只有这里定义时的16才表示16个字节

DATAp(16TYPE DECIMALS 14 VALUE '12345678901234567.89012345678901'.

"正负符号与小数点固定要占用半个字节,一个字面上位置,并包括在这16个字节里面。
"16 * 2 = 32位包括了小数点与在正负号在内
"在定义时字面上容许最长能够达到32位,除去小数点与符号需占半个字节之后
"有效数字位可容许31位,这31位中包括了整数位与小数位,再除去定义时小
"数位为14位外,整数位最多还可达到17位,因此下面最多只能是179
DATAp1(16TYPE DECIMALS 14 VALUE '-99999999999999999'.

 

"P类型是以字符串来表示一个数的,与字符串不同的是,P类型中的每一个数字位只会占用4Bit位,因此两个数字位才会占用一个字节。另外,若是定义时没有指定小数位,表示是整型,但小数点固定要占用半个字节,因此不带小数位与符号的最大与最小整数以下(最多容许319,而不是32个)
DATA: p1(16TYPE p  VALUE '+9999999999999999999999999999999'.
DATA: p2(16TYPE p  VALUE '-9999999999999999999999999999999'.

 

其实P类型是以字符串形式来表示一个小数,这样才能够做到精确,就像Java中要表示一个精确的小数要使用BigDecimal同样,不然会丢失精度。

DATAp(9TYPE DECIMALS VALUE '-123456789012345.12'.
WRITE/ p."123456789012345.12-

 

DATAf1 TYPE VALUE '2.0',
      f2 
TYPE VALUE '1.1',
      f3 
TYPE f.
f3  
=  f1 f2."不能精确计算
"2.0000000000000000E+00 1.1000000000000001E+00 8.9999999999999991E-01
WRITE/ f1   f2 f3.

DATAp1 TYPE DECIMALS VALUE '2.0',
      p2 
TYPE DECIMALS VALUE '1.1',
      p3 
TYPE DECIMALS 1.
p3  
=  p1 p2."能精确计算
WRITE/ p1   p2 p3. "2.0               1.1               0.9

 

Java中精确计算:

    publicstaticvoid main(String[] args) {

        System.out.println(2.0 - 1.1);// 0.8999999999999999

        System.out.println(sub(2.0, 0.1));// 1.9

    }

    publicstaticdouble sub(double v1, double v2) {

        BigDecimal b1 = new BigDecimal(Double.toString(v1));

        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.subtract(b2).doubleValue();

    }

1.2.TYPELIKE

透明表(还有其它数据词典中的类型,如结构)便可看做是一种类型,也可看做是对象,因此便可使用TYPE,也能够使用LIKE

TYPES type6 TYPE mara-matnr.
TYPES type7 LIKE mara-matnr.
DATA obj6 TYPE mara-matnr.
DATA obj7 LIKE mara-matnr.

"SFLIGHT为表类型
DATA plane LIKE sflight-planetype.
DATA plane2 TYPE sflight-planetype.
DATA plane3 LIKE sflight.
DATA plane4 TYPE sflight.
"syst为结构类型
DATA sy1 TYPE syst.
DATA sy2 LIKE syst.
DATA sy3 TYPE syst-index.
DATA sy4 LIKE syst-index.

 

注:定义的变量名千万别与词典中的类型相同,不然表面上便可使用TYPE也可以使用LIKE,就会出现这两个关键字(TypeLike)均可用的奇怪现像下面是定义一个变量时与词典中的结构同名的后果(致使)

DATA : BEGIN OF address2,
  street(
20TYPE c,
  city(
20TYPE c,
END OF address2.
DATA obj4 TYPE STANDARD TABLE OF address2."这里使用的实质上是词典中的类型address2
DATA obj5 LIKE STANDARD TABLE OF address2."这里使用是的上面定义的变量address2

上面程序编译经过,按理obj4定义是经过不过的(只能使用LIKE来引用另外一定义变量的类型,TYPE是不能够的),但因为address2是数字词典中定义的结构类型,因此obj4使用的是数字词典中的结构类型,而obj5使用的是LIKE,因此使用的是address2变量的类型

1.3.  DESCRIBE

DESCRIBE FIELD dobj 
  [
TYPE typ [COMPONENTS com]] 
  [
LENGTH ilen IN {BYTE|CHARACTERMODE
  [
DECIMALS dec] 
  [
OUTPUT-LENGTH olen] 
  [
HELP-ID hlp] 
  [
EDIT MASK mask].


DESCRIBE TABLE itab [KIND knd] [LINES lin] [OCCURS n].

1.4.字符串表达式

能够使用&&&将多个字符模板串连接起来,能够突破255个字符的限制,下面两个是等效的:

|...| &  |...|

|...| && |...|

若是内容只有字面常量文本(没有变量表达式或控制字符\r \n \t),则不须要使用字符模板,可这样(若是包含了这些控制字符时,会原样输出,因此有这些控制字符时,请使用 |...|将字符包起来):

`...` && `...`

可是上面3个与下面3个是不同的:

`...` &  `...`

'...' &  '...'

'...' && '...'

上面前两个仍是会受255个字符长度限制,最后一个虽然不受255限制,但尾部空格会被忽略

字面常量文本literal text)部分,使用 ||括起来,不能含有控制字符(如 \r \n \t这些控制字符),特殊字符 |{ } \须要使用 \进行转义:

txt |Characters \|\{and \} have to be escaped by \\ in literal text.|.

字符串表达式

str |{ }|."算术计算表达式
str |{ |aa| && 'bb' }|."字符串表达式

str |{ str }|."变量名

str |{ strlenstr }|."内置函数

1.5.  Data elementDomain

数据元素是构成结构、表的基本组件域又定义了数据元素的技术属性Data element主要附带Search HelpParameter ID、以及标签描述,而类型是由Domain域来决定的。Domain主要从技术方面描述了Data element,如Data Type数据类型、Output Length输出长度、Convers. Routine转换规则、以及Value Range取值范围

将技术信息从Data element提取出来为Domain域的好处:技术信息造成的Domain能够共用,而每一个表字段的业务含意不同,会致使其描述标签、搜索帮助不同,因此牵涉到业务部分的信息直接Data element中进行描述,而与业务无关的技术信息部分则分离出来造成Domain

 

 

 

1.6.  词典预约义类型与ABAP类型映射

当你在ABAP程序中引用了ABAPDictionary则预置Dictionary类型则会转换为相应的ABAP类型,预置的Dictionary类型转换规则表以下

 

Dictionarytype

Meaning

Maximumlengthn

ABAPtype

DEC

Calculation/amountfield

1-31, 1-17intables

P((n+1)/2)

INT1

Single-byte integer

3

Internalonly

INT2

Two-byteinteger

5

Internalonly

INT4

Four-byteinteger

10

I

CURR

Currencyfield货币字段

1-17

P((n+1)/2)

CUKY

Currencykey货币代码

5

C(5)

QUAN

Amount金额

1-17

P((n+1)/2)

UNIT

Unit单位

2-3

C(n)

PREC

Accuracy

2

X(2)

FLTP

Floating pointnumber

16

F(8)

NUMC

Numeric text数字字符

1-255

N(n)

CHAR

Character字符

1-255

C(n)

LCHR

Long character

256-max

C(n)

STRING

Stringofvariable length

1-max

STRING.

RAWSTRING

Byte sequence of variable length

1-max

XSTRING

DATS

Date

8

D

ACCP

Accounting period YYYYMM

6

N(6)

TIMS

Time HHMMSS

6

T

RAW

Byte sequence

1-255

X(n)

LRAW

Long byte sequence

256-max

X(n)

CLNT

Client

3

C(3)

LANG

Language

internal 1, external 2

C(1)

这里的“容许最大长度m”表示的是字面上容许的字符位数,而不是指底层所占内存字节数,如

int1的取值为0~255,因此是3位(不包括符号位)

int2的取值为-32768~32767,因此是5

lLCHR and LRAW类型容许的最大值为INT2 最大值

lRAWSTRING and STRING 具备可变长度,最大值能够指定,但没有上限

lSSTRING 长度是可变的,其最大值必须指定且上限为255。与CHAR类型相比其优点是它与ABAP type string进行映射。

这些预置的Dictionary类型在建立Data elementDomain时能够引用

Unicode系统中,一个字符占两个字节

1.7.字符串处理

SPLIT dobj AT sep INTO { {result1 result2 ...} | {TABLE result_tab} }必须指定足够目标字段。不然,用字段dobj的剩余部分填充最后目标字段并包含分界符;或者使用内表动态接收

SHIFT dobj {[{BY num PLACES}|{UP TO sub_string}][[LEFT|RIGHT][CIRCULAR]]}
           | { 
{LEFT DELETING LEADING}|{RIGHT DELETING TRAILING} pattern

对于固定长度字符串类型,shift产生的空位会使用空格或十六进制的0(若是为X类型串时)来填充

向右移动时前面会补空格,固定长度类型字符串与String结果是不同:String类型右移后不会被截断,只是字串前面补相应数量的空格,但若是是C类型时,则会截断;左移后后面是否被空格要看是不是固定长度类型的字符串仍是变长的String类型串,左移后C类型会补空格,String类型串不会(会缩短)

CIRCULAR:将移出的字符串放在左边或者左边

pattern:只要前导或尾部字符在指定的pattern字符集里就会被去掉,直到第一个不在模式pattern的字符止

CONDENSE <c> [NO-GAPS].若是是C类型只去掉前面的空格(由于是定长,即便后面空格去掉了,左对齐时后面会补上空格),若是是String类型,则后面空格也会被去掉;字符串中间的多个连续的空格使用一个空格替换(String类型也是这样)NO-GAPS:字符串中间的全部空格都也都会去除(String类型也是这样);空格去掉后会左对齐[kənˈdens] 

CONCATENATE {dobj1 dobj2 ...}|{LINES OF itab}[kənˈkatɪneɪt]
            INTO result
            [
SEPARATED BY sep]
            [
RESPECTING BLANKS].

CDNT类型的前导空格会保留,尾部空格都会被去掉,但对String类型全部空格都会保留;对于c, d, n, t类型的字符串有一个RESPECTING BLANKS选项可以使用,表示尾部空格也会保留。注:使用 `` String类型进行赋值时才会保留尾部空格  字符串链接能够使用 && 来操做,具体请参考这里

strlen(arg)Xstrlen(arg)String类型的尾部空格会计入字符个数中,但C类型的变量尾部空格不会计算入

substringval TEXT [off off] [len len] )

count( val TEXT {sub substring}|{regex regex} )匹配指定字符串substring或正则式regex出现的子串次数,返回的类型为i整型类型

containsval TEXT REGEX REGEX)是否包含。返回布尔值,注:只能用在ifWhile等条件表达式中

matchesval TEXT REGEX REGEX)regex表达式要与text彻底匹配,这与contains是不同的。返回布尔值,也只能用在ifWhile等条件表达式中

matchval TEXT REGEX REGEX occ occ)返回的为匹配到的字符串。注:每次只匹配一个。occ:表示需匹配到第几回出现的子串。若是为正,则从头日后开始计算,若是为负,则从尾部向前计算

findval TEXT {sub substring}|{regex regex}[occ occ] )查找substring或者匹配regex的子串的位置。若是未找到,则返回 -1,返回的为offset,因此从0开始

FIND ALL OCCURRENCES OF REGEX regex IN  dobj
  [
MATCH COUNT  mcnt]   成功匹配的次数
  { {[MATCH OFFSET moff][MATCH LENGTH mlen]}最后一次总体匹配到的串(总体串,最外层分组,而不是指正则式最内最后一个分组)起始位置与长度
  | [RESULTS result_tab|result_wa] } result_tab接收全部匹配结果,result_wa只能接收最后一次匹配结果
  [SUBMATCHES s1 s2 ...].一般与前面的MATCH OFFSET/ LENGTH一块儿使用。只会接收使用括号进行分组的子组。若是变量s1 s2 ...比分组的数量多,则多余的变量被initial;若是变量s1 s2 ...比分组的数量少,则多余的分组将被忽略;且只存储第一次或最后一次匹配到的结果

replaceval TEXT  REGEX REGEX  WITH NEW)使用new替换指定的子符串,返回String类型

REPLACE ALL OCCURRENCES OF REGEX regex IN  dobj WITH new

1.7.1.   countmatch结合

DATAtext TYPE string VALUE `Cathy's cat with the hat sat on Matt's mat.`,
      regx 
TYPE string VALUE `\<.at\>`."\< 单词开头\> 单词结尾
DATAcounts TYPE i,
index TYPE i,
      substr 
TYPE string.
WRITE text.
NEW-LINE.
counts 
countval text regex regx )."返回匹配次数
DO counts TIMES.
index findval   text regex regx occ sy-index )."返回匹配到的的起始位置索引
  substr 
matchval  text regex regx occ sy-index )."返回匹配到的串
index index 1.
WRITE AT index substr.
ENDDO.

1.7.2.FIND …SUBMATCHES 

DATAmoff TYPE i,
       mlen 
TYPE i,
       s1   
TYPE string,
       s2   
TYPE string,
       s3   
TYPE string,
       s4   
TYPE string.
FIND ALL OCCURRENCES OF REGEX `((\w+)\W+\2\W+(\w+)\W+\3)`"\2 \3 表示反向引用前面匹配到的第二与第三个子串
IN `Hey hey, my my, Rock and roll can never die Hey hey, my my`"会匹配二次,但只会返回第二次匹配到的结果,第一次匹配到的子串不会存储到s1s2s3中去
IGNORING CASE
MATCH OFFSET moff
 MATCH LENGTH mlen
SUBMATCHES s1 s2 s3 s4."根据从外到内,从左到右的括号顺序依次存储到s1 s2…中,注:只取出使用括号括起来的子串,如想取总体子串则也要括起来,这与Java不一样
WRITE/  s1/ s2,/ s3 ,/ s4,/ moff ,/ mlen."s4会被忽略

1.7.3.   FIND …RESULTS  itab

DATAresult TYPE STANDARD TABLE OF string WITH HEADER LINE .
"Java不一样,只要是括号括起来的都称为子匹配(即便用总体也用括号括起来了),
"无论括号嵌套多少层,统称为子匹配,且匹配到的全部子串都会存储到,
"MATCH_RESULT-SUBMATCHES中,即便最外层的括号匹配到的子串也会存储到SUBMATCHES
"内表中。括号解析的顺序为:从外到内,从左到右的优先级顺序来解析匹配结构。
"Java中的group(0)存储的是总体匹配串,即便总体未(或使用)使用括号括起来
PERFORM get_match TABLES result
USING '2011092131221032' '(((\d{2})(\d{2}))(\d{2})(\d{2}))'.
LOOP AT result .
WRITE/ result.
ENDLOOP.
FORM get_match  TABLES p_result"返回全部分组匹配(括号括起来的表达式)
USING    p_str
                         p_reg
.
DATAresult_tab TYPE match_result_tab WITH HEADER LINE.
DATAsubresult_tab TYPE submatch_result_tab WITH HEADER LINE.
"注意:带表头时 result_tab 后面必定要带上中括号,不然激活时出现奇怪的问题
FIND ALL OCCURRENCES OF REGEX p_reg IN p_str RESULTS result_tab[].
"result_tab中存储了匹配到的子串自己(与Regex总体匹配的串,存储在
"result_tab-offsetresult_tab-length中)以及所子分组(括号部分,存储在
"result_tab-submatches中)
LOOP AT result_tab .
"如需取总体匹配到的子串(与Regex总体匹配的串),则使用括号将总体Regex括起来
"来便可,括起来后也会自动存储到result_tab-submatches,而不须要在这里像这样读取
*    p_result = p_str+result_tab-offset(result_tab-length).
*    APPEND p_result.
    subresult_tab[] 
result_tab-submatches.
LOOP AT subresult_tab.
      p_result 
p_str+subresult_tab-offset(subresult_tab-length).
APPEND p_result.
ENDLOOP.
ENDLOOP.
ENDFORM.

 

1.7.4.正则式类

regex = Regular expression   [ˈreɡjulə]

cl_abap_regexJava中的 java.util.regex.Pattern的类对应

cl_abap_matcherJava中的 java.util.regex.Matcher的类对应

1.7.4.1.matchesmatch

是否彻底匹配正则式中没必要使用 ^ $);matches为静态方法match为实例方法做用都是同样

DATAmatcher TYPE REF TO cl_abap_matcher,
      match 
TYPE match_result,
      match_line 
TYPE submatch_result.
"^$能够省略由于matches方法自己就是彻底匹配整个Regex
IF cl_abap_matcher=>matchespattern '^(db(ai).*)$' text 'dbaiabd' ) = 'X'.
  matcher 
cl_abap_matcher=>get_object( )."获取最后一次匹配到的 Matcher 实例
  match 
matcher->get_match( ). "获取最近一次匹配的结果(是总体匹配的结果)
WRITE / matcher->text+match-offset(match-length).
LOOP AT  match-submatches INTO match_line"提取子分组括号括起来的部分
WRITE/20 match_line-offsetmatch_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.

DATAmatcher TYPE REF TO cl_abap_matcher,
      match 
TYPE match_result,
      match_line 
TYPE submatch_result.
"^$能够省略,由于matche方法自己就是彻底匹配整个Regex
matcher 
cl_abap_matcher=>createpattern '^(db(ai).*)$' text 'dbaiabd' ).
IF matcher->match(  ) = 'X'.
  match 
matcher->get_match( ). "获取最近一次匹配的结果
WRITE / matcher->text+match-offset(match-length).
LOOP AT  match-submatches INTO match_line"提取子分组(括号括起来的部分)
WRITE/20 match_line-offsetmatch_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.

1.7.4.2.contains

是否包含也可在正则式中使用 ^ $ 用于彻底匹配检查或者使用 ^ 检查是否匹配开头或者使用 $ 匹配结尾

DATAmatcher TYPE REF TO cl_abap_matcher,
      match 
TYPE match_result,
match_line 
TYPE submatch_result.
IF cl_abap_matcher=>containspattern '(db(ai).{2}b)' text 'dbaiabddbaiabb' ) = 'X'.
  matcher 
cl_abap_matcher=>get_object( ). "获取最后一次匹配到的 Matcher 实例
  match 
matcher->get_match( ). "获取最近一次匹配的结果
WRITE / matcher->text+match-offset(match-length).
  
LOOP AT  match-submatches INTO match_line"提取子分组(括号括起来的部分)
WRITE/20 match_line-offsetmatch_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.

1.7.4.3.find_all

一次性找出全部匹配的子串,包括子分组(括号括起的部分)

DATAmatcher TYPE REF TO cl_abap_matcher,
       match_line 
TYPE submatch_result,
      itab 
TYPE match_result_tab WITH HEADER LINE.
matcher 
cl_abap_matcher=>createpattern '<[^<>]*(ml)>' text '<html>hello</html>' )."建立 matcher 实例
":子分组存储在itab-submatches字段里
itab[] matcher->find_all( ).
LOOP AT itab .
WRITE/ matcher->textitab-offsetitab-length,matcher->text+itab-offset(itab-length).
  LOOP AT  itab-submatches INTO match_line"提取子分组(括号括起来的部分)
WRITE/20 match_line-offsetmatch_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDLOOP.

1.7.4.4.find_next

逐个找出匹配的子串,包括子分组(括号括起的部分)

DATAmatcher TYPE REF TO cl_abap_matcher,
      match 
TYPE match_result, match_line TYPE submatch_result,
      itab 
TYPE match_result_tab WITH HEADER LINE.
matcher 
cl_abap_matcher=>createpattern '<[^<>]*(ml)>' text '<html>hello</html>' ).
WHILE matcher->find_next( ) = 'X'.
  match 
matcher->get_match( )."获取最近一次匹配的结果
WRITE/ matcher->textmatch-offsetmatch-length,matcher->text+match-offset(match-length).  
  
LOOP AT  match-submatches INTO match_line. "提取子分组(括号括起来的部分)
 
WRITE/20 match_line-offsetmatch_line-length,matcher->text+match_line-offset(match_line-length).
  ENDLOOP.
ENDWHILE.

1.7.4.5.get_lengthget_offsetget_submatch

DATAmatcher TYPE REF TO cl_abap_matcher,
      length 
TYPE i,offset TYPE i,
      submatch 
TYPE string.
matcher 
cl_abap_matcher=>createpattern '(<[^<>]*(ml)>)' text '<html>hello</html>' ).
WHILE matcher->find_next( ) = 'X'. "循环2
"0时,表示取整个Regex匹配到的子串,这与Java同样,但若是整个Regex使用括号括起来后,
"则分组索引为1,这又与Java不同(Java无论是否使用括号将整个Regex括起来,分组索引号都为0
  "
上面Regex中共有两个子分组,再加上整个Regex为隐含分组,因此一共为3
DO TIMES.
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串长度
    length 
matcher->get_lengthsy-index ).
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串起始位置
    offset 
matcher->get_offsetsy-index ).
"在当前匹配到的串(整个Regex相匹配的串)中返回指定子分组的匹配到的字符串
    submatch 
matcher->get_submatchsy-index ).
WRITE:/ length offset,matcher->text+offset(length),submatch.
ENDDO.
SKIP.
ENDWHILE.

1.7.4.6.replace_all

DATAmatcher TYPE REF TO cl_abap_matcher,
      count
 TYPE i,
      repstr 
TYPE string.
matcher 
cl_abap_matcher=>createpattern '<[^<>]*>' text '<html>hello</html>' ).
count
 matcher->replace_all``)."返回替换的次数
repstr 
matcher->text. "获取被替换后的新串
WRITEcount repstr.

1.8.CLEARREFRESHFREE

内表:若是使用有表头行的内表,CLEAR 仅清除表格工做区域。要重置整个内表而不清除表格工做区域,使用REFRESH语句或 CLEAR 语句CLEAR <itab>[].REFRESH加不加中括号都是只清内表,另外REFRESH是专为清内表的,不能清基本类型变量,但CLEAR能够

以上都不会释放掉内表所占用的空间,若是想初始化内表的同时还要释放所占用的空间,请使用:FREE <itab>.

1.9.ABAP程序中的局部与全局变量

报表程序中选择屏幕事件块(AT SELECTION-SCREEN)与逻辑数据库事件块、以及methods(类中的方法)、subroutinesFORM子过程)、function modulesFunction函数)中声明的变量为局部的,即在这些块里声明的变量不能在其余块里使用,但这些局部变量能够覆盖同名的全局变量;除这些处理块外,其余块里声明的变量都属于全局的(如报表事件块列表事件块、对话Module),效果与在程序最开头定义的变量效果是同样的,因此能够在其余处理块直接使用(但要注意的是,需遵照先定义后使用的原则,这种前后关系是从语句书写顺序来讲的,与事件块的自己运行顺序没有关系);另外,局部变量声明时,无论在处理块的任何地方,其效果都是至关于处理块里的全局变量,而不像其余语言如Java那样:局部变量的做用域能够存在于任何花括号{}之间(这就意味着局部变量在处理过程范围内是全局的),以下面的i,在ABAP语言中仍是会累加输出,而不会永远是1(在Java语言中会是1):

FORM aa.
DO 10 TIMES.
DATAi TYPE i VALUE 0.
1.
WRITEi.
ENDDO.
ENDFORM.

1.10.FormFunction

FormFunction中的TABLES参数,TYPELIKE后面只能接标准内表类型或标准内表对象,若是要使用排序内表或者哈希内表,则只能使用USINGForm)与CHANGING方式来代替。当把一个带表头的实参经过TABLES参数传递时,表头也会传递过去,若是实参不带表头或者只传递了表体(使用了[]时),系统会自动为内表参数变量建立一个局部空的表头

无论是以TABLES仍是以USINGForm非值CHANGE非值方式传递时,都是以引用方式(即别名,不是指地址,注意与Java中的传引用区别:Java实为传值,但传递的值为地址的值,而ABAP中传递的是否为地址,则要看实参是不是经过Type ref to定义的)传递;但若是USING值传递,则对形参数的修改不会改变实参,由于此时不是引用传递;但若是CHANGE值传递,对形参数的修改仍是会改变实参,只是修改的时机在Form执行或Function执行完后,才去修改

Form中经过引用传递时,USINGCHANGING彻底同样;但CHANGING为值传递方式时,须要在Form执行完后,才去真正修改实参变量的内容,因此CHANGING传值与传引用其结果都是同样:结果都修改了实参内容,只是修改的时机不太同样而已

1.10.1.FORM

FORM subr [TABLES t1 [{TYPE itab_type}|{LIKE itab}|{STRUCTURE struc}] 
t2 […]] 

[USING VALUE(p1)|p1 } [ { TYPE generic_type } 

| { LIKE <generic_fs>|generic_para }
TYPE {[LINE OF] complete_type}|{REF TO type} } 
| { 
LIKE {[LINE OF] dobj} | {REF TO dobj} }
STRUCTURE struc] 

{ VALUE(p2)|p2 } […]] 

[CHANGING{ VALUE(p1)|p1 } [ { TYPE generic_type } 

| { LIKE <generic_fs>|generic_para }  

| { TYPE {[LINE OF] complete_type} | {REF TO type} } 
| { 
LIKE {[LINE OF] dobj} | {REF TO dobj} } 
|
STRUCTURE struc] 

{ VALUE(p2)|p2 } […]] 

[RAISING {exc1|RESUMABLE(exc1)} {exc2|RESUMABLE(exc2)} ...].

generic_type:为通用类型

complete_type:为彻底限制类型

<generic_fs>:为字段符号变量类型,以下面的 fs 形式参数

generic_para:为另外一个形式参数类型,以下面的 b 形式参数

DATAd(10VALUE'11'.
FIELD-SYMBOLS<fs> LIKE d.
ASSIGN TO <fs>.
PERFORM aa USING <fs> d d.
FORM aa USING fs like <fs>  a like b like a.
WRITE:fs,/ a / b.
ENDFORM.

若是没有给形式参数指定类,则为ANY类型

若是TABLESUSINGCHANGING一块儿使用时,则必定要按照TABLESUSINGCHANGING顺序声明

值传递中的VALUE关键字只是在FORM定义时出现,在调用时PERFORM语句中无需出现,也就是说,调用时值传递和引用传递不存在语法格式差异

 

DATA : i TYPE i VALUE 100.
WRITE: / 'frm_ref===='.
PERFORM frm_ref USING i .
WRITE: / i."200

WRITE: / 'frm_val===='.
i = 100.
PERFORM frm_val USING i .
WRITE: / i."100

WRITE: / 'frm_ref2===='.

"不能将下面的变量定义到frm_ref2过程当中,若是这样,下面的dref指针在调用frm_ref2 后,指向的是Form中局部变量内存,为不安全发布,运行会抛异常,由于From结束后,它所拥有的全部变量内存空间会释放掉
DATA: i_frm_ref2 TYPE i VALUE 400.
i = 100.
DATA: dref TYPE REF TO i .
get REFERENCE OF i INTO dref.
PERFORM frm_ref2 USING dref ."传递的内容为地址,属于别名引用传递
WRITE: / i."4000

field-SYMBOLS : <fs> TYPE i .
ASSIGN dref->* to <fs>."因为frm_ref2过程当中已修改了dref的指向,现指向了i_frm_ref2 变量的内存空间
WRITE: / <fs>."400

WRITE: / 'frm_val2===='.
i = 100.
DATA: dref2 TYPE REF TO i .
get REFERENCE OF i INTO dref2.
PERFORM frm_val2 USING dref2 .
WRITE: / i."4000
ASSIGN dref2->* to <fs>.
WRITE: / <fs>."4000

FORM frm_ref  USING  p_i TYPE i ."C++中的引用参数传递p_i为实参i的别名
WRITE: /  p_i."100
  p_i = 
200."p_i为参数i的别名,因此能够直接修改实参
ENDFORM.   

FORM frm_val  USING   value(p_i)."传值p_i为实参i的拷贝
WRITE: /  p_i."100
  p_i = 
300."因为是传值,因此不会修改主调程序中的实参的值
ENDFORM.
FORM frm_ref2 USING p_i TYPE REF TO i ."p_i为实参dref的别名,相似C++中的引用参数传递(传递的内容为地址,而且属于别名引用传递)
field-SYMBOLS : <fs> TYPE i .
"如今<fs>就是实参所指向的内存内容的别名,表明实参所指向的实际内容
ASSIGN p_i->* to <fs>.
WRITE: /  <fs>."100
<fs> = 
4000."直接修改实参所指向的实际内存


DATA: dref TYPE REF TO i .
get REFERENCE OF i_frm_ref2 INTO dref.
"因为USINGC++的引用参数,因此这里修改的直接是实参所存储的地址内容,这里的p_i为传进来的dref的别名,是同一个变量,因此实参的指向也发生了改变(这与Java中传递引用是不同的,Java中传递引用时为地址的拷贝,即Java中永远也只有传值,但C/C++/ABAP中能够传递真正引用——别名)
  p_i = dref.
"此处会修改实参的指向 
ENDFORM.

FORM frm_val2 USING VALUE(p_i) TYPE REF TO i ."p_i为实参dref2的拷贝,相似Java中的引用传递(虽然传递的内容为地址,但传递的方式属于地址拷贝——值传递)
field-SYMBOLS : <fs> TYPE i .
"如今<fs>就是实参所指向的内存内容的别名,表明实参所指向的实际内容
ASSIGN p_i->* to <fs>.
WRITE: /  <fs>."100
<fs> = 
4000."但这里仍是能够直接修改实参所指向的实际内容


DATA: dref TYPE REF TO i .
get REFERENCE OF i_frm_ref2 INTO dref.
"这里与过程 frm_ref2 不同,该过程 frm_val2 参数的传递方式与java中的引用传递是原理是同样的:传递的是地址拷贝,因此下面不会修改主调程序中实参dref2的指向,它所改变的只是拷贝过来的Form中局部形式参数的指向
  p_i = dref.  
ENDFORM.

1.10.2.FUNCTION

1.10.2.1.       Function Group结构

当使用Function Builder建立函数组时,系统会自动建立main program与相应的include程序:

l<fgrp>Function Group的名称

lSAPL<fgrp>为主程序名,它将Function Group里的全部Include文件包括进来,除了INCLUDE语句以外,没有其余语句了

lL<fgrp>TOP,里面有FUNCTION-POOL语句,以及全部Function Module均可以使用的全局数据定义

lL<fgrp>UXX,也只有INCLUDE语句,它所包括的Include文件为相应具体Function Module所对应Include文件名:L<fgrp>U01L<fgrp>U02...这些Include文件实际上包含了所对应的Function Module代码(即双击它们进去就是对应的Function,而显示的不是真正Include文件所对应的代码)

lL<fgrp>U01L<fgrp>U02中的0102编号对应L<fgrp>UXX中的“XX”,表明其建立前后的序号,例如L<fgrp>U01L<fgrp>U02是头两个被建立的函数,在函数组中建立出的函数代码就放在相应的L<fgrp>UXX(这里的XX表明某个数字,而不是字面上的XXInclude头文件中

lL<fgrg>FXX,用来存一些Form子过程,而且能够被全部Function Modules所使用(不是针对某个Function Module的,但通常在设计时会针对每一个Function Module设计这样单独的Include文件,这是一个好习惯),而且在使用时不须要在Function Module中使用INCLUDE语句包含它们(由于这些文件在主程序SAPL<fgrp>里就已经被Include进来了)。另外,L<fgrg>FXX中的F是指Form的意思,这是一种名称约束而已,在建立时咱们能够随便指定,通常还有IXX(表示些类Include文件包括的是一些PAI事件中调用的Module,有时干脆直接使用L<fgrg>PAI或者L<fgrg>PAIXX),OXX(表示些类Include文件包括的是一些PBO事件中调用的Module,有时干脆直接使用L<fgrg>PBO或者L<fgrg>PBOXX)。注:若是Form只被某一函数单独使用,实质上还可直接将这些Form定义在Function Module里的ENDFUNCTION语句后面

 

当你调用一个function module时,系统加将整个function group(包括Function ModuleInclude文件等)加载到主调程序所在的internal session中,而后该Function Module获得执行,该Function Group一直保留在内存中,直到internal session结束。Function Group中的所定义的Include文件中的变量是全局,被全部Function Module共享,因此Function Group比如Java中的类,而Function Module则比如类中的方法,因此Function Group中的Include文件中定义的东西是全局型的,能被全部Function Module所共享使用

1.10.2.2.Function参数传值、传址

function fuc_ref .
*"-------------------------------------------------------------------
*"*"Local Interface:
*"  IMPORTING
*"     REFERENCE(I_I1) TYPE  IREFERENCE别名为参数的默认传递类型
*"     VALUE(I_I2) TYPE  I        定义时勾选了Pass Value选项才会是 VALUE类型
*"     REFERENCE(I_I3) TYPE REF TO  I
*"     VALUE(I_I4) TYPE REF TO  I
*"  EXPORTING
*"     REFERENCE(E_I1) TYPE  I
*"     VALUE(E_I2) TYPE  I
*"     REFERENCE(E_I3) TYPE REF TO  I
*"     VALUE(E_I4) TYPE REF TO  I
*"  TABLES
*"      T_1 TYPE  ZJZJ_ITAB
*"  CHANGING
*"     REFERENCE(C_I1) TYPE  I
*"     VALUE(C_I2) TYPE  I
*"     REFERENCE(C_I3) TYPE REF TO  I
*"     VALUE(C_I4) TYPE REF TO  I
*"-------------------------------------------------------------------
write: / i_i1."1
"因为i_i1为输入类型参数且又是引用类型实参不能被修改。这里i_i1是以C++中的引用(别名)参数方式传递参数,因此若是修改了i_i1就会修改实际参数,因此函数中不能修改REFERENCE  IMPORTING类型的参数,若是去掉下面注释则编译出错
"i_i1 = 10.

write: / i_i2."2
"虽然i_i2是输入类型的参数,但不是引用类型,因此能够修改,编译能经过但不会修改外面实参的值,只是修改了该函数局部变量的值
i_i2 = 20.

field-symbols: <fs> type i .
assign i_i3->* to <fs>.
"因为i_i3存储的是地址,因此先要解引用再能使用
write: / <fs>.
"同上面,REFERENCEIMPORTING类型的参数不能被修改:这里即不能修改实参的指向"GET REFERENCE OF 30 INTO i_i3."虽然不能够修改实参的指向,但能够修改实参所指向的实际内容
<fs> = 
30.

assign i_i4->* to <fs>.
"i_i4存储也的是地址,因此先要解引用再能使用
write: / <fs>.
"虽然i_i4是输入类型的参数,但不是引用类型,因此能够修改,只会修改函数中的局部参数i_i4的指向,但并不会修改实参的指向
get reference of 40 into i_i4.
"虽然不能修改实参的指向,但能够直接修改实参的所指向的实际内容
<fs> = 
400.

WRITE: / c_i1."111
"c_i1为实参的别名,修改形参就等于修改实参内容
c_i1 = 
1110.

WRITE: / c_i2."222
"c_i2为实参的副本,因此不会影响实参的内容,可是,因为是CHANGING类型的参数,且为值传递,在函数正常执行完后,仍是会将该副本再次拷贝给实参,因此最终实参仍是会被修改
c_i2 = 
2220.
ENDFUNCTION.

 

调用程序:

DATA: i_i1 TYPE i VALUE 1,
      i_i2 
TYPE i VALUE 2,
      i_i3 
TYPE REF TO i ,
      i_i4 
TYPE REF TO i ,
      c_i1 
TYPE i VALUE 111,
      c_i2 
TYPE i VALUE 222,
      c_i3 
TYPE REF TO i ,
      c_i4 
TYPE REF TO i ,
      t_1 
TYPE zjzj_itab WITH HEADER LINE.

DATA: i_i3_ TYPE i VALUE 3.
GET REFERENCE OF i_i3_ INTO i_i3.
DATA: i_i4_ TYPE i VALUE 4.
GET REFERENCE OF i_i4_ INTO i_i4.
DATA: c_i3_ TYPE i VALUE 333.
GET REFERENCE OF c_i3_ INTO c_i3.
DATA: c_i4_ TYPE i VALUE 444.
GET REFERENCE OF c_i4_ INTO c_i4.

CALL FUNCTION 'FUC_REF'
EXPORTING
    i_i1 = i_i1
    i_i2 = i_i2
    i_i3 = i_i3
    i_i4 = i_i4
TABLES
    t_1 = t_1
CHANGING
    c_i1 = c_i1
    c_i2 = c_i2
    c_i3 = c_i3
    c_i4 = c_i4.
WRITE: / i_i2."2
WRITE: / i_i3_."30
WRITE: / i_i4_."400
WRITE: / c_i1."1110
WRITE: / c_i2."2220

1.11.     字段符号FIELD-SYMBOLS

字段符号能够看做仅是已经被解引用的指针(相似于C语言中带有解引用操做符 * 的指针),但更像是C++中的引用类型(int i ;&ii= i;),即某个变量的别名,它与真正的指针仍是有很大的区别的,在ABAP中引用变量(经过TYPE REF TO定义的变量)才比如C语言中的指针

ASSIGN ... TO <fs>:将某个内存区域分配给字段符号,这样字段符号就表明了该内存区域,即该内存区域别名

1.11.1.ASSIGN隐式强转

TYPESBEGIN OF t_date,
  year(
4TYPE  n,
  month(
2TYPE n,
  day(
2TYPE n,
END OF t_date.

FIELD-SYMBOLS <fs> TYPE t_date."<fs>定义成了具体限定类型
ASSIGN sy-datum TO <fs> CASTING. "后面没有指定具体类型,因此使用定义时的类型进行隐式转换

1.11.2.ASSIGN显示强转

DATA txt(8TYPE c VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs> CASTING TYPE d."因为定义时未指定具体的类型,因此这里须要显示强转

1.11.3.ASSIGN 动态分配

请参考动态语句à ASSIGN 动态分配

1.11.4.UNASSIGNCLEAR

UNASSIGN:该语句是初始化<FS>字段符号,执行后字段符号将再也不引用内存区域,<fs> is assigned返回假

CLEAR:与UNASSIGN不一样的是,只有一个做用就是初始化它所指向的内存区域,而不是解除分配

1.12.数据引用、对象引用

TYPE REF TO data                     数据引用data references

TYPE REF TO object               对象引用object references

除了object全部的通用类型都能直接用TYPE后面TYPE data但没有TYPE object,object不能直接跟在TYPE后面只能跟在TYPE REF TO后面

TYPE REF TO 后面可接的通用类型只能data(数据引用)或者是object对象引用通用类型其余通用类型不行

1.12.1.数据引用Data References

DATAdref TYPE REF TO i ."dref即为数据引用,即数据指针,指向某个变量或常量,存储变量地址
CREATE DATA dref.
dref
->2147483647."可直接解引用使用不须要先经过分配给字段符号后再使用

DATABEGIN OF strct,
c,
END OF strct.
DATAdref LIKE REF TO strct .
CREATE DATA dref .
dref
->*-'A'.

 

TYPEStpy TYPE c.
DATAc1 TYPE REF TO tpy.
DATAc2 LIKE REF TO c1."二级指针
GET REFERENCE OF 'a' INTO c1.
GET REFERENCE OF c1 INTO c2.
WRITEc2->*->*."a

1.12.2.对象引用Object references

CLASS cl DEFINITION.
PUBLIC SECTION.
DATAi VALUE 1.
ENDCLASS.
CLASS cl IMPLEMENTATION.
ENDCLASS.

 

DATAobj TYPE REF TO cl.
CREATE OBJECT obj. "建立对象

DATAoref LIKE REF TO obj. "oref即为对象引用,即对象指针,指向某个对象,存储对象地址
GET REFERENCE OF obj INTO oref. "获取对象地址
WRITEoref->*->i."1

1.12.3.GET REFERENCE OF获取变量/对象/常量地址

DATAe_i3 TYPE REF TO i .
GET REFERENCE OF 33 INTO e_i3.
WRITEe_i3->*."33
"但不能修改常量的值
"e_i3->* = 44.

DATAi TYPE i VALUE 33,
      dref 
LIKE REF TO i."存储普通变量的地址
GET REFERENCE OF i INTO dref.
dref
->44.
WRITEi"44

1.13.动态语句

1.13.1.内表动态访问

SORT itab BY (comp1)...(compn)

 

READ TABLE itab WITH KEY(k1)=v1...(kn)=vn

READ TABLE itab...INTOwaCOMPARING(comp1)...(compn) TRANSPORTING(comp1)...

MODIFY [TABLE] itab TRANSPORTING(comp1)...(compn)

DELETE TABLEitabWITH TABLE KEY(comp1)...(compn)

DELETE ADJACENT DUPLICATES FROM itab COMPARING(comp1)...(compn)

 

AT NEW/END OF (comp)

1.13.2.动态类型

CREATE DATA ... TYPE (type)...

DATA: a TYPE REF TO i.
CREATE DATA a TYPE ('I').
a->* = 1.

CREATE OBJECT ... TYPE (type)...请参考类对象反射章节

1.13.3.动态SQL

Select请参照后面的动态SQL

MODIFY/UPDATE(dbtab)...

1.13.4.动态调用类的方法

CALL METHOD (meth_name)
            | cref->(meth_name)
            | iref->(meth_name)
            | (class_name)=>(meth_name)
            | class=>(meth_name)
            | (class_name)=>meth

实例请参考类对象反射章节

1.13.5.ASSIGN 动态分配

FIELD-SYMBOLS:<fs>.

DATA:str(20TYPE c VALUE 'Output String',
     name
(20TYPE c VALUE 'STR'.

"静态分配:编译时就知道要分配的对象名
ASSIGN name TO <fs>."结果<fs>name变量等同

"经过变量名动态访问变量
ASSIGN (nameTO <fs>."结果是是<fs>的值为str变量值

 

DATABEGIN OF line,
  col1 
TYPE i VALUE '11',
  col2 
TYPE i VALUE '22',
  col3 
TYPE i VALUE '33',
END OF line.
DATA comp(5VALUE 'COL3'.
FIELD-SYMBOLS<f1><f2><f3>.
ASSIGN line TO <f1>.
ASSIGN comp TO <f2>.

"还可以直接使用如下的语法访问其余程序中的变量
ASSIGN ('(ZJDEMO)SBOOK-FLDATE'TO <fs>.

"经过索引动态的访问结构成员
ASSIGN COMPONENT sy-index OF STRUCTURE <f1> TO <f3>.

"经过字段名动态的访问结构成员
ASSIGN COMPONENT <f2>OF STRUCTURE <f1> TO <f3>.

"若是定义的内表没有组件名时,能够使用索引为0的组件来访问这个无名字段(注:不是1)
ASSIGN COMPONENT 0 OF STRUCTURE itab TO  <fs>.

1.13.5.1.动态访问类的属性成员

ASSIGN oref->('attr') TO <attr>.
ASSIGN oref->('static_attr') TO <attr>.
ASSIGN ('C1')=>('static_attr') TO <attr>.
ASSIGN c1=>('static_attr') TO <attr>.
ASSIGN ('C1')=>static_attr TO <attr>.

实例请参考类对象反射章节

1.14.反射

CL_ABAP_TYPEDESCR

  |--CL_ABAP_DATADESCR

  |   |--CL_ABAP_ELEMDESCR

  |   |--CL_ABAP_REFDESCR

  |   |--CL_ABAP_COMPLEXDESCR

  |       |--CL_ABAP_STRUCTDESCR

  |       |--CL_ABAP_TABLEDESCR

  |--CL_ABAP_OBJECTDESCR

     |--CL_ABAP_CLASSDESCR

     |--CL_ABAP_INTFDESCR

DATA: structtype  TYPE REF TO cl_abap_structdescr.
structtype ?= cl_abap_typedescr=>describe_by_name'spfli' ).

*COMPDESC-TYPE ?= CL_ABAP_DATADESCR=>DESCRIBE_BY_NAME( 'EKPO-MATNR' ).

DATA: datatype TYPE REF TO cl_abap_datadescr,
field(5TYPE c.
datatype ?= cl_abap_typedescr=>describe_by_datafield ).

 

DATA: elemtype TYPE REF TO cl_abap_elemdescr.
elemtype = cl_abap_elemdescr=>get_i( ).
elemtype = cl_abap_elemdescr=>
get_c20 ).

 

DATAoref1 TYPE REF TO object.
DATAdescr_ref1 TYPE REF TO cl_abap_typedescr.
CREATE OBJECT oref1 TYPE ('C1'). "C1为类名
descr_ref1 
cl_abap_typedescr=>describe_by_object_ref( oref1 ).

还有一种:describe_by_data_ref

1.14.1.TYPE HANDLE

handle只能是CL_ABAP_DATADESCR或其子类的引用变量只能用于Data类型,不能用于Object类型即不能用于CL_ABAP_ OBJECTDESCR因此没有:

CREATE OBJECT dref TYPE HANDLE objectDescr.

 

DATAdref TYPE REF TO data,
c10type 
TYPE REF TO cl_abap_elemdescr.
c10type 
cl_abap_elemdescr=>get_c10 ).
CREATE DATA dref TYPE HANDLE c10type.

DATAx20type TYPE REF TO cl_abap_elemdescr.
x20type 
cl_abap_elemdescr=>get_x20 ).
FIELD-SYMBOLS<fs> TYPE any.
ASSIGN dref->TO <fs> CASTING TYPE HANDLE x20type.

1.14.2.动态建立数据Data或对象Object

  TYPESty_i TYPE i.
DATAdref TYPE REF TO ty_i .
 CREATE DATA dref TYPE ('I')."根据基本类型名动态建立数据
  dref->1.
WRITE/ dref->*." 1

  CREATE OBJECT oref TYPE ('C1')."根据类名动态建立实例对象

1.14.3.动态建立基本类型变量、结构、内表

DATAdref_str TYPE REF TO data,
      dref_tab 
TYPE REF TO data,
      dref_i 
TYPE REF TO data,
  itab_type 
TYPE REF TO cl_abap_tabledescr,
  struct_type 
TYPE REF TO cl_abap_structdescr,
  elem_type 
TYPE REF TO cl_abap_elemdescr,
  table_type 
TYPE REF TO cl_abap_tabledescr,
  comp_tab 
TYPE cl_abap_structdescr=>component_table WITH HEADER LINE.
FIELD-SYMBOLS :<fs_itab> TYPE ANY TABLE.

**=========动态建立基本类型
elem_type ?= cl_abap_elemdescr=>get_i( ).
CREATE DATA dref_i TYPE HANDLE elem_type ."动态的建立基本类型数据对象

**=========动态建立结构类型
struct_type ?= cl_abap_typedescr
=>describe_by_name'SFLIGHT' )."结构类型
comp_tab[] 
struct_type->get_components( )."组成结构体的各个字段组件
向结构中动态的新增一个成员
comp_tab-name 'L_COUNT'."为结构新增一个成员
comp_tab-type elem_type."新增成员的类型对象
INSERT comp_tab INTO comp_tab INDEX 1.
动态建立结构类型对象
struct_type 
cl_abap_structdescr=>createcomp_tab[] ).
CREATE DATA dref_str TYPE HANDLE struct_type."使用结构类型对象来建立结构对象

**=========动态建立内表
基于结构类型对象建立内表类型对象
itab_type cl_abap_tabledescr=>createstruct_type ).
CREATE DATA dref_tab TYPE HANDLE itab_type."使用内表类型对象来建立内表类型
ASSIGN dref_tab->TO <fs_itab>."将字段符号指向新建立出来的内表对象

"**========给现有的内表动态的加一列
table_type ?= cl_abap_tabledescr
=>describe_by_dataitab ).
struct_type ?= table_type
->get_table_line_type( ).
comp_tab[] 
struct_type->get_components( ).
comp_tab
-name 'FIDESC'.
comp_tab
-type cl_abap_elemdescr=>get_c120 ).
INSERT comp_tab INTO comp_tab INDEX 2.
struct_type 
cl_abap_structdescr=>createcomp_tab[] ).
itab_type 
cl_abap_tabledescr=>createstruct_type ).
CREATE DATA dref_tab TYPE HANDLE itab_type.

1.14.4.类对象反射

CLASS c1 DEFINITION.
PUBLIC SECTION.
DATAc VALUE 'C'.
METHODStest.
ENDCLASS.

CLASS c1 IMPLEMENTATION.
METHOD:test.
WRITE:'test'.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
TYPESty_c.
DATAoref TYPE REF TO object .
DATAoref_classdescr TYPE REF TO cl_abap_classdescr .
CREATE OBJECT oref TYPE ('C1')."根据类名动态建立实例对象
"至关于Java中的Class类对象
 oref_classdescr ?= cl_abap_classdescr
=>describe_by_object_reforef ).

DATAt_attrdescr_tab TYPE abap_attrdescr_tab WITH HEADER LINE,"类中的属性列表
        t_methdescr_tab 
TYPE abap_methdescr_tab WITH HEADER LINE."类中的方法列表
FIELD-SYMBOLS <fs_attr> TYPE any.
  t_attrdescr_tab[] 
oref_classdescr->attributes.
  t_methdescr_tab[] 
oref_classdescr->methods.
LOOP AT t_attrdescr_tab."动态访问类中的属性
ASSIGN oref->(t_attrdescr_tab-name) TO <fs_attr>.
    WRITE/ <fs_attr>.
ENDLOOP.
LOOP AT t_methdescr_tab."动态访问类中的方法
CALL METHOD oref->(t_methdescr_tab-name).
  ENDLOOP.

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

²TYPES, DATA, CLASS-DATA, CONSTANTS  for data types and data objects

²METHODS, CLASS-METHODS, EVENTS, CLASS-EVENTS for methods and events

²  INTERFACES若是在类中,表示须要实现哪一个接口;若是是在接口中,表示继承哪一个接口 for implementing interfaces

²  ALIASESfor 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 
/ 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>.[inˈherit]

 

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.

  s ?= p."向下强转型

2.6.  方法

METHODS/CLASS-METHODS meth [ABSTRACT|FINAL
    [
IMPORTING parameters [PREFERRED PARAMETER p]] 
    [
EXPORTING parameters
    [
CHANGING parameters
    [{
RAISING|EXCEPTIONS} exc1 exc2 ...].

应该还有一个Returning选项,RETURNING不能与EXPORTINGCHANGING同时使用

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 }...

²dataobject表示是通用数据类型dataobject

²complete_type为彻底限定类型

²OPTIONALDEFAULT两个选项不能同时使用且对于EXPORTING类型的输入参数不能使用

²若是参数名p1前没有使用VALUEREFERENCE默认为仍是REFERENCE即引用传递

²方法中的输入输出参数是否能修改请参考FormFunction参数的传值传址

2.6.2.   PREFERRED PARAMETER首选参数

设置多个IMPORTING类型参数中的某一个参数为首选参数。

首选参数的意义在于:当全部IMPORTING类型都为可选optional时,咱们能够经过PREFERRED PARAMETER选项来指定某一个可选输入参数为首选参数,则在如下简单方式调用时:[CALL METHOD] meth). 实参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不能与EXPORTINGCHANGING同时使用

[EXCEPTIONS [exc1 = n1 exc2 = n2 ...]

[OTHERS = n_others] ] [)].

若是省略CALL METHOD,则必定要加上括号形式若是经过CALL METHOD来调用,则括号可加可不加

RECEIVING:用来接收METHODS /CLASS-METHODS RETURNING选项返回的值

若是EXPORTINGIMPORTINGCHANGINGRECEIVINGEXCEPTIONSOTHERS同时出现时,应该按此顺序来编写

使用此种方式调用(使用 EXPORTINGIMPORTING等这些选项)时,若是原方法声明时带了返回值RETURNING,只能使用RECEIVING来接受,而不能使用等号来接收返回值,下面用法是错误的:

num2 o1->m1EXPORTING p1 num1 ).

2.6.4.   简单调用

此方式下输入的参数都只能是IMPORTING类型的参数,若是要传CHANGINGEXPORTINGRAISINGEXCEPTIONS类型的参数时,只能使用上面通用调用方式

²meth( )

此种方式仅适用于没有输入参数IMPORTING输入\输出参数CHANGING或者有但都是可选的、或者不是可选时但有默认值也可

²meth( a )

此种方式仅适用于只有一个必选输入参数IMPORTING)(若是还有其余输入参数,则其余都为可选,或者不是可选时但有默认值也可),或者是有多个可选输入参数IMPORTING)(此时没有必选输入参数状况下)的状况下但方法声明时经过使用PREFERRED PARAMETER选项指定了其中某个可选参数为首选参数(首选参数即在使用meth( a )方式传递一个参数进行调用时,经过实参a传递给设置为首选的参数

²meth( p1 = a1 p2 = a2 ... )

此种方式适用于有多个必选的输入参数IMPORTING)方法的调用(其它如CHANGINGEXPORTING没有,或者有但可选),若是输入参数(IMPORTING)为可选,则也能够没必要传

2.6.5.函数方法

Return惟一返回值

METHODS meth
    [IMPORTING
parameters [PREFERRED PARAMETER p]]
    RETURNINGVALUE(r) typing
    [{RAISING|EXCEPTIONS} exc1 exc2 ...].

 

RETURNING 用来替换EXPORTINGCHANGING不能同时使用。定义了一个形式参数 r 来接收返回值而且只能是值传递

具备惟一返回值的函数方法能够直接用在如下语句中逻辑表达式IFELSEIFWHILECHECKWAITCASELOOP、算术表达式、赋值语句

函数方法能够采用上面简单调用方式来调用meth( )meth( a )meth( p1 = a1 P2 = a2 ... )

 

  ref->mRECEIVING  r ).
CALL METHOD ref->mRECEIVING r ).
CALL METHOD ref->RECEIVING r i.

2.7.mesuper

等效于Java中的 thissuper

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) ...].

²dataobject:表示是通用数据类型dataobject

²complete_type:为彻底限定类型

²  OPTIONALDEFAULT两个选项不能同时使用

²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(p1TYPE string value(p2TYPE 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.
EVENTSe1 EXPORTING value(p1TYPE c,e2.
CLASS-EVENTS ce1 EXPORTING value(p2TYPE i.
METHODS:trigger."事件触发方法
ENDCLASS.

CLASS  c1 IMPLEMENTATION.
METHOD trigger.
RAISE EVENTe1 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.
"非静态方法处理非静态事件此方法属于非静态处理器只能采用非静态注册方式
METHODSh2 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.
METHODh2.
WRITE'c2->h2'.
ENDMETHOD.
METHODh3.
WRITE'c2->h3'.
ENDMETHOD.
ENDCLASS.

DATAtrigger 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.
  "因为h1h2两个处理方法分别是用来处理非静态事件e1e2的,因此只能采用实例注册方式
SET HANDLERc2=>h1 handler->h2 FOR trigger,
"h3处理方法是用来处理静态事件ce1的,属于静态处理器,因此只能采用静态注册方式
                 handler
->h3.
  trigger
->trigger( ).
  "虽然trigger( )方法会触发 e1,e2,ce1 三种事件,但h1h2未向实例trigger2注册,而h3属于静态处理器,与实例无关,即比如向全部实例注册过了同样
  trigger2
->trigger( ).

3.   内表

3.1.LOOP AT循环内表

LOOP AT itab {INTO wa}|{ASSIGNING <fs> [CASTING]}|{TRANSPORTING NO FILDS
[[
USING KEY key_name|(name)] [FROM idx1] [TO idx2] [WHERE log_exp|(cond_syntax)]]

ENDLOOP.

FROM … TO: 只适用于标准表与排序表          WHERE …  : 适用于全部类型的内表

若是没有经过USING KEY选项的key_name则循环读取的顺序与表的类型相关

l标准表与排序表会按照primary table index索引的顺序一条条的循环且在循环里SY-TABIX为当前正在处理行的索引号

l  哈希表因为表没有排序因此按照插入的顺序来循环处理,注,此时SY-TABIX 老是0

能够在循环内表时增长与删除当前行If you insert or delete lines in the statement block of a LOOP , this will have the following effects:

  • If you insert lines behind(后面) the current line, these new lines will be processed in the subsequent loop(新行会在下一次循环时被处理) passes. An endless loop(可能会引发死循环)can result
  • If you delete lines behind the current line, the deleted lines will no longer be processed in the subsequent loop passes
  • If you insert lines in front(前面) of the current line, the internal loop counter is increased by one with each inserted line. This affects sy-tabix in the subsequent loop pass(这会影响在随后的循环过程SY-TABIX)
  • If you delete lines in front of the current line, the internal loop counter is decreased by one with each deleted line. This affects sy-tabix in the subsequent loop pass

3.1.1.循环中删除行

DATA : BEGIN OF gt_table OCCURS 0,

       c,

END OF gt_table.

 

APPEND 'a' TO gt_table.

APPEND 'b' TO gt_table.

APPEND 'c' TO gt_table.

APPEND 'd' TO gt_table.

APPEND 'e' TO gt_table.

APPEND 'f' TO gt_table.

APPEND 'g' TO gt_table.

APPEND 'h' TO gt_table.

 

LOOP AT gt_table .

  IF gt_table-c = 'b' OR gt_table-c = 'c' OR gt_table-c = 'e'.

    WRITE : /  sy-tabix COLOR = 6 INTENSIFIED ON INVERSE OFF ,

               gt_table COLOR = 6 INTENSIFIED ON INVERSE OFF .

  ELSE.

    WRITE : /  sy-tabix, gt_table.

  ENDIF.

ENDLOOP.

 

SKIP 2.

DATA count TYPE i .

LOOP AT gt_table .

  count = count + 1.

  "当循环到第三次时删除,即循环到 C 时进行删除

  IF count = 3.

    DELETE gt_table WHERE c = 'b' OR c = 'c' OR c = 'e'.

  ENDIF.

  "删除以后sy-tabix会从新开始对内表现有的行进行编号

  WRITE :/ sy-tabix, gt_table.

ENDLOOP.

 

SKIP 2.

 

LOOP AT gt_table .

    WRITE : /  sy-tabix, gt_table.

ENDLOOP.

 

 

3.1.2.SUM

若是在 AT - ENDAT 块中使用 SUM则系统计算当前行组中全部行的数字字段之和并将其写入工做区域中相应的字段中

3.1.3.    AT...ENDAT

<line>

含义

FIRST

内表的第一行时触发

LAST

内表的最后一行时触发

NEW <f>

相邻数据行中相同<f>字段构成一组,在循环到该组的开头时触发

END Of <f>

相邻数据行中相同<f>字段构成一组,在循环到该组最末时触发

在使用AT...... ENDAT以前,一这要先按照这些语句中的组件名进行排序,且排序的顺序要与在AT...... ENDAT语句中使用顺序一致,排序与声明的顺序决定了先按哪一个分组,接着再按哪一个进行分组,最后再按哪一个进行分组,这与SQL中的Group By 类似

用在AT...... ENDAT语句中的中的组件名不必定要是结构中的关键字段,但这些字段必定要按照出如今AT关键字后面的使用顺序在结构最前面进行声明,且这些组件字段的声明之间不能插入其余组件的声明如如今须要按照<f1>, <f2>, ....多个字段的顺序来使用在AT...... ENDAT语句中,则首先须要在结构中按照<f1>, <f2>, ....,多字段的顺序在结构最前面都声明,而后按照<f1>, <f2>, ....,多字段来排序的,最后在循环中按以下的顺序块书写程序(请注意书写AT END OF的顺序与AT NEW 是相反的,像下面这样):

LOOP AT <itab>.

AT FIRST. ... ENDAT.

AT NEW <f1>. ...... ENDAT.

AT NEW <f2>. ...... ENDAT.

.......

<single line processing>

.......

AT END OF <f2>.... ENDAT.

AT END OF <f1>. ... ENDAT.

AT LAST. .... ENDAT.

ENDLOOP.

一旦进入到 AT...<f1>...ENDAT 块中时,当前工做区(或表头)中的从<f1>日后,但不包括<f1>(按照在结构中声明的次序)全部字段的字符类型字段会以星号(*)号来填充,而数字字设置为初始值(注:在测试过程当中发现String类型不会使用*来填充,而是设置成empty String,因此只有固定长度类型的非数字基本类型才设置为*)。若是在 AT 块中使用了SUM,则会将全部数字类型字段统计出来将存入当前工做区(或表头);但一旦离开AT....ENDAT块后,又会将当前遍历的行恢复到工做区(或表头)中

  DATABEGIN OF th_mseg OCCURS 10,
matnr 
TYPE mard-matnr, werks TYPE mard-werks,
lgort 
TYPE mard-lgort, shkzg TYPE mseg-shkzg,
      menge 
TYPE mseg-menge, budat TYPE mkpf-budat,
LOOP AT th_mseg.
AT END OF shkzg."会根据shkzg及前面全部字段来进行分组
sum.
WRITE: / th_mseg-matnr, th_mseg-werks,th_mseg-lgort,
             th_mseg-shkzg,th_mseg-menge,th_mseg-budat.
ENDAT.
ENDLOOP.

AS-101             2300 0001 S           10.000  ****.**.**

AS-100             2300 0002 S           10.000  ****.**.**

AS-100             2300 0001 S           20.000  ****.**.**

上面因为没有根据matnr + werks + lgort + shkzg 进行排序,因此结果中的第三行其实应该与第一行合并。其实这个统计与SQL里的分组(Group By)统计原理是同样的,Group By 后面须要明确指定分组的字段,如上面程序使用SQL分组写法应该为 Group Bymatnr werks lgort shkzg,但在ABAP里你只须要按照 matnr werks lgort shkzg按照前后顺序在结构定义的最前面进行声明就可表达了Group By那种意义,并且不必定要将matnr werks lgort shkzg这四个字段所有用在AT语句块中AT NEWAT END OF shkzg 才正确,其实像上面程序同样,只写AT END OF shkzg这一个语句,前面三个字段matnr werks lgort均可以不用在AT语句中出现,由于ABAP默认会按照结构中声明的顺序将shkzg前面的字段也全都用在了分组中了

 

DATABEGIN OF line,
"C2C3组件名声明的顺序必定要与在AT...... ENDAT块中使用的次序一致,即这里不能将C3声明在C2以前,且不能在C2C3之间插入其余字段的声明
      c2
(5TYPE c,
      c3
(5TYPE c,
      c4
(5TYPE c,
      i1 
TYPE i,
      i2 
TYPE i,
      c1
(5TYPE c,
END OF line.

"使用在AT...... ENDAT语句中的字段不必定要是关键字段
DATAitab LIKE TABLE OF line WITH HEADER LINE WITH NON-UNIQUE KEY i1.
PERFORM append USING 'b' 'bb' 'bbb' '2222' 22.PERFORM append USING 'c' 'aa' 'aaa' '3333' 33.
PERFORM append USING 'd' 'aa' 'bbb' '4444' 44.PERFORM append USING 'e' 'bb' 'aaa' '5555' 55.
PERFORM append USING 'f' 'bb' 'bbb' '6666' 66.PERFORM append USING 'g' 'aa' 'aaa' '7777' 77.
PERFORM append USING 'h' 'aa' 'bbb' '8888' 88.
SORT itab ASCENDING BY c2 c3.
LOOP AT itab.
WRITE/ itab-c2,itab-c3,itab-c1,itab-c4,itab-i1,itab-i2.
ENDLOOP.
SKIP.
LOOP AT itab.
AT FIRST.
WRITE:'>>>> AT FIRST'.
ENDAT.
  AT NEW c2.
WRITE'    >>>> Start of' itab-c2.
ENDAT.
  AT NEW c3.
WRITE'        >>>> Start of' itab-c2itab-