运行时类型服务 练习 #practice #rtts #rtti #rttc #dynamic-types #abap-objects
关键词
答案
RTTS
Run Time Type Services,运行时类型服务总称
RTTI
Run Time Type Identification,运行时类型识别
RTTC
Run Time Type Creation,运行时类型创建
根类
CL_ABAP_TYPEDESCR
describe_by_data
根据数据对象获取类型描述
describe_by_name
根据类型名获取类型描述
describe_by_object_ref
根据对象引用获取类描述
题目1 - RTTS 概述与组成 [记忆] 什么是 RTTS?它由哪两个部分组成?各自的功能是什么?
RTTS(Run Time Type Services) 是 ABAP 提供的运行时类型服务,允许程序在运行时检查和创建数据类型。
两个组成部分 :
组成
全称
功能
RTTI
Run Time Type Identification
在运行时识别和检查数据类型信息
RTTC
Run Time Type Creation
在运行时动态创建新的数据类型
核心类体系 :
1 2 3 4 5 6 7 8 9 CL_ABAP_TYPEDESCR " 类型描述基类 ├── CL_ABAP_ELEMDESCR " 基本类型(I, C, D, T, ...) ├── CL_ABAP_STRUCTDESCR " 结构体类型 ├── CL_ABAP_TABLEDESCR " 内表类型 ├── CL_ABAP_REFDESCR " 引用类型 ├── CL_ABAP_CLASSDESCR " 类类型 ├── CL_ABAP_INTFDESCR " 接口类型 ├── CL_ABAP_DATADESCR " 数据描述基类 └── CL_ABAP_ENUMDESCR " 枚举类型
RTTI 用于读取类型信息(属性、组件等),RTTC 用于动态创建类型描述对象并由此创建数据引用。
题目2 - CL_ABAP_TYPEDESCR 的静态方法 [记忆] CL_ABAP_TYPEDESCR 提供了哪些核心静态方法用于获取类型描述?请列出并说明各自的用途。
CL_ABAP_TYPEDESCR 核心静态方法 :
方法
用途
示例
DESCRIBE_BY_DATA( )
根据数据对象获取类型描述
获取变量的类型信息
DESCRIBE_BY_NAME( )
根据类型全名获取类型描述
获取已知类型名的描述
DESCRIBE_BY_OBJECT_REF( )
根据对象引用获取类描述
获取对象的类信息
DESCRIBE_BY_DATA_REF( )
根据数据引用获取类型描述
获取引用指向的数据类型
使用示例 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 DATA: lv_num TYPE i VALUE 42, lt_table TYPE STANDARD TABLE OF sflight. " 根据数据对象获取描述 DATA(lo_type) = cl_abap_typedescr=>describe_by_data( lv_num ). WRITE: / lo_type->type_kind, " 输出: 'I' (整数类型) lo_type->absolute_name. " 输出: 'I' " 根据类型名获取描述 DATA(lo_struct) = cl_abap_structdescr=>describe_by_name( 'SFLIGHT' ). " 根据对象引用获取描述 DATA(lo_obj) = NEW zcl_my_class( ). DATA(lo_class) = cl_abap_typedescr=>describe_by_object_ref( lo_obj ). WRITE: / lo_class->absolute_name. " 输出: 'ZCL_MY_CLASS'
返回类型为 CL_ABAP_TYPEDESCR 的引用,可根据需要向下转型为具体子类。
题目3 - type_kind 属性值含义 [记忆] CL_ABAP_TYPEDESCR 的 type_kind 属性返回单字符类型代码。请列出常见的 type_kind 值及其含义。
type_kind 常见值 :
type_kind
含义
对应 ABAP 类型
I
整数
TYPE I
P
压缩小数
TYPE P
F
浮点数
TYPE F
C
字符
TYPE C / N
N
数字文本
TYPE N
D
日期
TYPE D
T
时间
TYPE T
X
十六进制
TYPE X
g
字符串
TYPE STRING
y
字节串
TYPE XSTRING
u
结构体(扁平)
TYPES: BEGIN OF …
v
结构体(深层)
含字符串/内表组件
h
内表
TYPE TABLE / STANDARD TABLE
r
数据引用
TYPE REF TO DATA
l
对象引用
TYPE REF TO object
k
类引用
TYPE REF TO class
e
枚举类型
TYPE ENUM
题目4 - 结构体类型描述 [记忆] 如何使用 CL_ABAP_STRUCTDESCR 获取结构体的组件信息?请写出代码示例并说明返回的组件表结构。
获取结构体组件信息 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 " 方式1:通过数据对象 DATA: ls_flight TYPE sflight. DATA(lo_struct) = CAST cl_abap_structdescr( cl_abap_typedescr=>describe_by_data( ls_flight ) ). " 方式2:通过类型名 DATA(lo_struct2) = CAST cl_abap_structdescr( cl_abap_structdescr=>describe_by_name( 'SFLIGHT' ) ). " 获取组件列表 DATA(lt_components) = lo_struct->get_components( ). " 遍历组件 LOOP AT lt_components INTO DATA(ls_comp). WRITE: / ls_comp-name, " 组件名(如 CARRID) ls_comp-type->type_kind, " 类型代码(如 'C') ls_comp-type->length. " 长度 ENDLOOP.
组件表(COMPONENT_TABLE)结构 :
字段
类型
说明
NAME
STRING
组件名称
TYPE
REF TO CL_ABAP_DATADESCR
组件的类型描述引用
AS_INCLUDE
ABAP_BOOL
是否为 INCLUDE 结构
SUFFIX
STRING
INCLUDE 的后缀
DECIMALS
I
小数位数(仅 P 类型)
TYPE_KIND
TYPEKIND
内部类型代码
其他有用的方法 :
GET_COMPONENT( iv_name ) — 获取指定名称的组件
GET_SYMBOL_TABLE( ) — 获取符号表
STRUCT_KIND 属性 — 结构类型(FLAT/DEEP)
题目5 - 内表类型描述 [记忆] 如何使用 CL_ABAP_TABLEDESCR 获取内表的类型信息(如表类型、行类型、键定义)?
内表类型描述 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 DATA: lt_flights TYPE SORTED TABLE OF sflight WITH NON-UNIQUE KEY carrid connid. " 获取内表类型描述 DATA(lo_table) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( lt_flights ) ). " 获取行类型 DATA(lo_line_type) = lo_table->get_table_line_type( ). WRITE: / '行类型:', lo_line_type->absolute_name. " SFLIGHT " 获取表类别 CASE lo_table->table_kind. WHEN cl_abap_tabledescr=>tablekind_std. WRITE: / '标准表'. WHEN cl_abap_tabledescr=>tablekind_sorted. WRITE: / '排序表'. WHEN cl_abap_tabledescr=>tablekind_hashed. WRITE: / '哈希表'. WHEN cl_abap_tabledescr=>tablekind_any. WRITE: / '任意表类型'. ENDCASE. " 获取键信息 DATA(lt_keys) = lo_table->key. LOOP AT lt_keys INTO DATA(ls_key). WRITE: / '键组件:', ls_key-name. ENDLOOP. " 检查唯一性 IF lo_table->has_unique_key = abap_true. WRITE: / '键是唯一的'. ENDIF.
CL_ABAP_TABLEDESCR 关键属性 :
属性
说明
TABLE_KIND
表类别(STD/SORTED/HASHED)
KEY
键组件表
HAS_UNIQUE_KEY
键是否唯一
INITIAL_SIZE
初始大小
题目6 - describe_by_object_ref 使用 [记忆] describe_by_object_ref 和 describe_by_class_name 有什么区别?在什么场景下使用 describe_by_object_ref?
两种方法对比 :
方法
输入
返回
用途
describe_by_object_ref
对象引用实例
对象实际运行时类的描述
获取对象运行时类型
describe_by_class_name
类名字符串
指定名称的类描述
按名称查询类信息
关键区别 :
describe_by_object_ref 返回的是对象的 实际运行时类型 (考虑多态)
describe_by_class_name 返回的是 指定名称 的类描述
多态场景示例 :
1 2 3 4 5 6 7 8 9 10 11 12 DATA: lo_animal TYPE REF TO lcl_animal. " 实际创建的是子类 lcl_dog 的实例 lo_animal = NEW lcl_dog( ). " describe_by_object_ref 返回 lcl_dog 的描述 DATA(lo_type) = cl_abap_typedescr=>describe_by_object_ref( lo_animal ). WRITE: / lo_type->absolute_name. " 输出: LCL_DOG(而非 LCL_ANIMAL) " describe_by_class_name 返回指定类的描述 DATA(lo_type2) = cl_abap_classdescr=>describe_by_class_name( 'LCL_ANIMAL' ). WRITE: / lo_type2->absolute_name. " 输出: LCL_ANIMAL
使用场景 :
多态编程中确定对象的实际类型
动态方法调用前检查对象是否实现了某个接口
调试和日志记录中获取对象的类名
题目7 - RTTC 动态创建数据类型 [记忆] 什么是 RTTC(Run Time Type Creation)?如何使用 RTTC 动态创建结构体类型和内表类型?
RTTC 概念 :
RTTC 允许在运行时动态创建新的数据类型,并使用这些类型创建数据引用。
动态创建结构体类型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 " 定义组件 DATA(lt_components) = VALUE cl_abap_structdescr=>component_table( ( name = 'ID' type = cl_abap_elemdescr=>get_i( ) ) ( name = 'NAME' type = cl_abap_elemdescr=>get_c( 20 ) ) ( name = 'PRICE' type = cl_abap_elemdescr=>get_p( p_length = 10 p_decimals = 2 ) ) ). " 创建结构体类型 DATA(lo_struct_type) = cl_abap_structdescr=>create( lt_components ). " 创建数据引用并分配 DATA: lo_data TYPE REF TO data. CREATE DATA lo_data TYPE HANDLE lo_struct_type. " 使用字段符号访问 FIELD-SYMBOLS: <ls_data> TYPE any. ASSIGN lo_data->* TO <ls_data>. ASSIGN COMPONENT 'ID' OF STRUCTURE <ls_data> TO FIELD-SYMBOL(<lv_id>). <lv_id> = 100.
动态创建内表类型 :
1 2 3 4 5 6 7 8 9 10 " 基于已创建的结构体类型创建内表类型 DATA(lo_table_type) = cl_abap_tabledescr=>create( p_line_type = lo_struct_type p_table_kind = cl_abap_tabledescr=>tablekind_std p_unique = abap_false ). " 创建内表数据引用 CREATE DATA lo_table TYPE HANDLE lo_table_type. FIELD-SYMBOLS: <lt_table> TYPE ANY TABLE. ASSIGN lo_table->* TO <lt_table>.
关键方法 :
CL_ABAP_ELEMDESCR=>GET_I( ) — 获取基本类型描述
CL_ABAP_ELEMDESCR=>GET_C( length ) — 获取字符类型描述
CL_ABAP_STRUCTDESCR=>CREATE( components ) — 创建结构体
CL_ABAP_TABLEDESCR=>CREATE( ... ) — 创建内表
题目8 - RTTI 与 RTTC 协作分析 [分析] 分析以下场景:一个程序需要从外部配置表读取字段定义(字段名、类型、长度),然后动态创建对应的内表并填充数据。请说明 RTTI 和 RTTC 在此场景中分别扮演什么角色,以及完整的处理流程。
场景分析:RTTI + RTTC 协作 RTTI 的角色(读取已有类型信息) :
从配置表中读取的字段类型名(如 ‘CHAR’, ‘INT’)需要转换为对应的类型描述对象
可使用 CL_ABAP_ELEMDESCR=>DESCRIBE_BY_NAME( ) 获取基本类型信息
RTTC 的角色(动态创建新类型) :
根据配置动态组合组件,创建新的结构体类型
基于结构体类型创建内表类型
使用 CREATE DATA ... TYPE HANDLE 创建实际的数据对象
完整流程 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 " 第1步:从配置表读取字段定义(数据层) SELECT field_name, abap_type, length, decimals FROM zfield_config INTO TABLE @DATA(lt_config). " 第2步:使用 RTTC 构建组件表 DATA: lt_components TYPE cl_abap_structdescr=>component_table. LOOP AT lt_config INTO DATA(ls_conf). DATA(lo_elem) = cl_abap_elemdescr=>get_c( ls_conf-length ). " 根据类型分发 CASE ls_conf-abap_type. WHEN 'CHAR'. lo_elem = cl_abap_elemdescr=>get_c( ls_conf-length ). WHEN 'INT'. lo_elem = cl_abap_elemdescr=>get_i( ). WHEN 'PACK'. lo_elem = cl_abap_elemdescr=>get_p( p_length = ls_conf-length p_decimals = ls_conf-decimals ). ENDCASE. APPEND VALUE #( name = ls_conf-field_name type = lo_elem ) TO lt_components. ENDLOOP. " 第3步:RTTC 创建动态结构体类型 DATA(lo_struct) = cl_abap_structdescr=>create( lt_components ). " 第4步:RTTC 创建动态内表类型 DATA(lo_table) = cl_abap_tabledescr=>create( lo_struct ). " 第5步:创建数据对象 DATA: lo_data_ref TYPE REF TO data. CREATE DATA lo_data_ref TYPE HANDLE lo_table. FIELD-SYMBOLS: <lt_dynamic> TYPE STANDARD TABLE. ASSIGN lo_data_ref->* TO <lt_dynamic>. " 第6步:填充数据(使用字段符号动态访问) DATA(lo_row_ref) = cl_abap_structdescr=>create( lt_components ). CREATE DATA lo_row TYPE HANDLE lo_row_ref. ASSIGN lo_row->* TO FIELD-SYMBOL(<ls_row>). ASSIGN COMPONENT 'FIELD1' OF STRUCTURE <ls_row> TO FIELD-SYMBOL(<lv_val>). <lv_val> = 'Hello'. APPEND <ls_row> TO <lt_dynamic>.
总结 :RTTI 识别现有类型 → RTTC 组合创建新类型 → CREATE DATA 实例化。
题目9 - 动态类型创建综合应用 [应用] 请编写完整的 ABAP 程序:根据输入参数动态创建一个包含任意数量字段的结构体,然后创建对应的内表,插入若干行数据,并使用 RTTI 输出内表的类型信息。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 REPORT zrttc_dynamic_table. PARAMETERS: p_fields TYPE i DEFAULT 3. START-OF-SELECTION. PERFORM create_dynamic_table. FORM create_dynamic_table. DATA: lt_components TYPE cl_abap_structdescr=>component_table. " 动态构建组件 DO p_fields TIMES. DATA(lv_name) = |FIELD{ sy-index }|. DATA(lo_type) = COND #( WHEN sy-index = 1 THEN cl_abap_elemdescr=>get_i( ) WHEN sy-index = 2 THEN cl_abap_elemdescr=>get_c( 30 ) WHEN sy-index = 3 THEN cl_abap_elemdescr=>get_p( p_length = 10 p_decimals = 2 ) ELSE cl_abap_elemdescr=>get_c( 20 ) ). APPEND VALUE #( name = lv_name type = lo_type ) TO lt_components. ENDDO. " 创建结构体和内表类型 DATA(lo_struct) = cl_abap_structdescr=>create( lt_components ). DATA(lo_table_type) = cl_abap_tabledescr=>create( p_line_type = lo_struct p_table_kind = cl_abap_tabledescr=>tablekind_std ). " 创建数据对象 DATA: lo_table_ref TYPE REF TO data, lo_row_ref TYPE REF TO data. CREATE DATA lo_table_ref TYPE HANDLE lo_table_type. CREATE DATA lo_row_ref TYPE HANDLE lo_struct. FIELD-SYMBOLS: <lt_table> TYPE STANDARD TABLE, <ls_row> TYPE any. ASSIGN lo_table_ref->* TO <lt_table>. ASSIGN lo_row_ref->* TO <ls_row>. " 插入数据 DO 5 TIMES. ASSIGN COMPONENT 'FIELD1' OF STRUCTURE <ls_row> TO FIELD-SYMBOL(<lv_f1>). <lv_f1> = sy-index * 10. ASSIGN COMPONENT 'FIELD2' OF STRUCTURE <ls_row> TO FIELD-SYMBOL(<lv_f2>). <lv_f2> = |记录 { sy-index }|. APPEND <ls_row> TO <lt_table>. ENDDO. " 使用 RTTI 输出类型信息 DATA(lo_rtti) = cl_abap_tabledescr=>describe_by_data( <lt_table> ). DATA(lo_tab_info) = CAST cl_abap_tabledescr( lo_rtti ). WRITE: / '表类型:', SWITCH string( lo_tab_info->table_kind WHEN cl_abap_tabledescr=>tablekind_std THEN '标准表' WHEN cl_abap_tabledescr=>tablekind_sorted THEN '排序表' WHEN cl_abap_tabledescr=>tablekind_hashed THEN '哈希表' ). WRITE: / '行数:', lines( <lt_table> ). WRITE: / '--- 组件 ---'. DATA(lo_line) = lo_tab_info->get_table_line_type( ). LOOP AT CAST cl_abap_structdescr( lo_line )->get_components( ) INTO DATA(ls_comp). WRITE: / ls_comp-name, ls_comp-type->type_kind. ENDLOOP. ENDFORM.
题目10 - RTTI 用于通用编程 [应用] 请编写一个通用工具方法,接收任意内表参数,自动输出内表的元信息(行数、列数、每列名称和类型)。这体现了 RTTI 在通用编程中的什么价值?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 CLASS lcl_table_info DEFINITION. PUBLIC SECTION. CLASS-METHODS: display_info IMPORTING it_data TYPE ANY TABLE. ENDCLASS. CLASS lcl_table_info IMPLEMENTATION. METHOD display_info. " 获取内表类型描述 DATA(lo_table) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( it_data ) ). " 获取行类型 DATA(lo_line) = CAST cl_abap_structdescr( lo_table->get_table_line_type( ) ). " 获取组件 DATA(lt_comp) = lo_line->get_components( ). " 输出元信息 WRITE: / '===== 内表元信息 ====='. " 表类型 WRITE: / '表类型:', SWITCH string( lo_table->table_kind WHEN cl_abap_tabledescr=>tablekind_std THEN '标准表' WHEN cl_abap_tabledescr=>tablekind_sorted THEN '排序表' WHEN cl_abap_tabledescr=>tablekind_hashed THEN '哈希表' ). " 行数和列数 WRITE: / '行数:', lines( it_data ). WRITE: / '列数:', lines( lt_comp ). " 列详情 WRITE: / '--- 列详情 ---'. WRITE: / |{ '列名' WIDTH=20 } { '类型' WIDTH=6 } { '长度' WIDTH=6 }|. WRITE: / '-------------------------------------------'. LOOP AT lt_comp INTO DATA(ls_col). DATA(lv_type) = SWITCH string( ls_col-type->type_kind WHEN 'I' THEN 'INT' WHEN 'C' THEN 'CHAR' WHEN 'P' THEN 'PACK' WHEN 'D' THEN 'DATE' WHEN 'T' THEN 'TIME' WHEN 'g' THEN 'STRG' WHEN 'h' THEN 'TTAB' ELSE ls_col-type->type_kind ). WRITE: / |{ ls_col-name WIDTH=20 } { lv_type WIDTH=6 } | && |{ ls_col-type->length WIDTH=6 }|. ENDLOOP. ENDMETHOD. ENDCLASS. " 使用示例 START-OF-SELECTION. SELECT * FROM sflight INTO TABLE @DATA(lt_flights) UP TO 10 ROWS. lcl_table_info=>display_info( lt_flights ).
RTTI 在通用编程中的价值 :
真正的多态 :TYPE ANY TABLE 使方法可接受任意内表,RTTI 在运行时确定具体类型
消除重复代码 :一个方法处理所有内表,不需要为每种表结构写单独的版本
动态框架 :这是 ALV、序列化框架等通用组件的基础技术
调试工具 :快速检查任意数据对象的结构信息
元数据驱动 :基于类型信息自动生成 UI、文档或映射逻辑
这种模式在企业级 ABAP 开发中非常常见,特别是在框架和工具类的开发中。
关键词
答案
RTTS
运行时类型服务总称(RTTI + RTTC)
RTTI
运行时类型识别(读取类型信息)
RTTC
运行时类型创建(动态构建类型)
CL_ABAP_TYPEDESCR
类型描述根类
CL_ABAP_ELEMDESCR
基本类型描述
CL_ABAP_STRUCTDESCR
结构体类型描述
CL_ABAP_TABLEDESCR
内表类型描述
describe_by_data
根据数据对象获取描述
describe_by_name
根据类型名获取描述
describe_by_object_ref
根据对象引用获取描述
type_kind
单字符类型代码(I/C/P/D/h 等)
get_components
获取结构体组件列表
get_table_line_type
获取内表行类型
CREATE(RTTC)
动态创建类型描述
CREATE DATA … TYPE HANDLE
根据类型描述创建数据
通用编程
TYPE ANY/TABLE + RTTI 实现多态工具