OO语法基础 练习
OO语法基础 练习
#practice #oo-syntax #abap-objects
Related Concepts
📌核心模式
| 关键词 | 答案 |
|---|---|
| 类定义 | CLASS … DEFINITION / CLASS … IMPLEMENTATION |
| 可见性 | PUBLIC SECTION, PROTECTED SECTION, PRIVATE SECTION |
| 构造函数 | CONSTRUCTOR 方法,在 CREATE OBJECT 时自动调用 |
| 引用变量 | TYPE REF TO,指向对象的引用 |
题目1 - [记忆] 类定义的基本结构
请写出ABAP中定义和实现一个类的完整语法框架。
📌查看答案
1 | " 类定义(声明) |
关键点:
DEFINITION部分声明类的接口(属性、方法、事件)IMPLEMENTATION部分实现所有在定义中声明的方法- 类名约定:局部类以
LCL_开头,全局类以CL_开头
题目2 - [记忆] 三种可见性区域
请解释ABAP类中 PUBLIC SECTION、PROTECTED SECTION 和 PRIVATE SECTION 的区别。
📌查看答案
| 可见性 | 访问范围 | 用途 |
|---|---|---|
| PUBLIC SECTION | 所有外部程序、子类和类本身均可访问 | 定义外部接口,提供公共服务 |
| PROTECTED SECTION | 仅限类本身及其子类(继承者)访问 | 为子类提供可复用的内部方法和属性 |
| PRIVATE SECTION | 仅限类本身访问,子类也无法直接访问 | 隐藏内部实现细节,保护数据完整性 |
设计原则:
- 属性通常设为 PRIVATE,通过公有方法提供受控访问(getter/setter)
- 供子类重定义的方法放在 PROTECTED SECTION
- 对外提供的服务接口放在 PUBLIC SECTION
- 遵循最小可见性原则:尽可能使用最严格的可见性
题目3 - [记忆] 实例属性与静态属性
请说明实例属性(Instance Attribute)和静态属性(Static Attribute)的区别。
📌查看答案
| 特性 | 实例属性 | 静态属性 |
|---|---|---|
| 声明 | DATA: attr TYPE type |
CLASS-DATA: attr TYPE type |
| 存在方式 | 每个对象实例各有一份独立的副本 | 整个类只有一份,所有实例共享 |
| 访问方式 | 通过对象引用访问:oref->attr |
通过类名访问:lcl_class=>attr,也可通过引用访问 |
| 生命周期 | 随对象的创建和销毁 | 类被加载时创建,程序运行期间一直存在 |
| 典型用途 | 存储对象的状态数据(如订单金额) | 计数器、配置信息、共享常量 |
示例:
1 | CLASS lcl_counter DEFINITION. |
题目4 - [记忆] 构造函数的作用和特点
请说明ABAP中构造函数(CONSTRUCTOR)的特点和用途。
📌查看答案
构造函数的特点:
- 名称固定:必须命名为
CONSTRUCTOR(实例构造函数)或CLASS_CONSTRUCTOR(静态构造函数) - 自动调用:在使用
CREATE OBJECT创建对象时自动被调用 - 初始化:用于设置对象的初始状态,初始化属性值
- 参数支持:可以定义 IMPORTING 参数和异常,在创建对象时传入初始值
- 不可继承:每个类必须定义自己的构造函数(但子类构造函数会隐式调用父类构造函数)
语法:
1 | METHODS: constructor IMPORTING iv_name TYPE string. |
静态构造函数(CLASS_CONSTRUCTOR):在类首次被访问时自动调用一次,仅用于初始化静态属性,不能有参数。
题目5 - [记忆] 引用变量和对象创建
请说明ABAP中如何声明引用变量、创建对象以及访问对象的属性和方法。
📌查看答案
声明引用变量:
1 | DATA: lo_customer TYPE REF TO lcl_customer. " 声明引用变量 |
创建对象:
1 | CREATE OBJECT lo_customer. " 创建对象实例 |
NEW 操作符(内联创建):
1 | DATA(lo_customer) = NEW lcl_customer( iv_name = 'John' ). |
访问属性和方法:
1 | " 实例成员使用 -> (对象组件选择器) |
关键概念:引用变量存储的是指向对象的指针(引用),而非对象本身。
题目6 - [记忆] 方法定义的参数类型
请列出ABAP方法中可以使用的四种参数类型(参数传递方式)及其特点。
📌查看答案
| 参数类型 | 关键字 | 特点 |
|---|---|---|
| 导入参数 | IMPORTING |
从调用者传入方法,方法内只读 |
| 导出参数 | EXPORTING |
从方法返回给调用者,方法内写入 |
| 变更参数 | CHANGING |
从调用者传入并可能被方法修改,可读写 |
| 返回参数 | RETURNING |
返回单个值,支持函数式调用链式写法 |
语法示例:
1 | METHODS: calculate_price |
注意:
RETURNING参数只能有一个,且不能与EXPORTING或CHANGING同时使用RETURNING参数使用VALUE()语法,表示按值传递- 推荐使用
RETURNING以支持函数式编程风格
题目7 - [应用] 编写类定义
请根据以下需求编写一个ABAP类的完整定义和实现:
- 类名:
lcl_product(商品类)- 有私有的商品名称和价格属性
- 构造函数接收名称和价格参数进行初始化
- 公有方法
get_price_with_tax返回含税价格(税率10%)
📌查看答案
1 | CLASS lcl_product DEFINITION. |
使用示例:
1 | DATA(lo_product) = NEW lcl_product( iv_name = '笔记本电脑' iv_price = '5999.00' ). |
题目8 - [应用] 方法调用分析
分析以下代码的执行结果。请逐步追踪
lo_ref引用变量的变化。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 CLASS lcl_demo DEFINITION.
PUBLIC SECTION.
METHODS: set_value IMPORTING iv_val TYPE i.
METHODS: get_value RETURNING VALUE(rv_val) TYPE i.
PRIVATE SECTION.
DATA: mv_value TYPE i.
ENDCLASS.
CLASS lcl_demo IMPLEMENTATION.
METHOD set_value. mv_value = iv_val. ENDMETHOD.
METHOD get_value. rv_val = mv_value. ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
DATA: lo_ref1 TYPE REF TO lcl_demo.
DATA: lo_ref2 TYPE REF TO lcl_demo.
CREATE OBJECT lo_ref1.
lo_ref1->set_value( 10 ).
lo_ref2 = lo_ref1.
lo_ref2->set_value( 20 ).
WRITE: / lo_ref1->get_value( ).
📌查看答案
输出结果:20
逐步分析:
CREATE OBJECT lo_ref1— 创建一个lcl_demo对象,lo_ref1指向该对象lo_ref1->set_value( 10 )— 将该对象的mv_value设置为 10lo_ref2 = lo_ref1— 关键步骤:将lo_ref1的引用赋值给lo_ref2,此时lo_ref1和lo_ref2指向同一个对象(不是创建新对象)lo_ref2->set_value( 20 )— 修改了同一对象的mv_value为 20lo_ref1->get_value( )— 返回该对象的mv_value,此时值为 20
核心概念:引用赋值(lo_ref2 = lo_ref1)不创建新对象,而是让两个引用变量指向同一块内存。通过任一引用修改对象,另一个引用也能看到变化。
题目9 - [应用] 静态成员使用场景
以下代码试图实现一个对象计数器。请找出代码中的错误并修正。
1
2
3
4
5
6
7
8
9
10
11
12
13
14 CLASS lcl_counter DEFINITION.
PUBLIC SECTION.
METHODS: constructor.
DATA: mv_count TYPE i.
PRIVATE SECTION.
CLASS-DATA: gv_instance_count TYPE i.
ENDCLASS.
CLASS lcl_counter IMPLEMENTATION.
METHOD constructor.
gv_instance_count = gv_instance_count + 1.
mv_count = gv_instance_count.
ENDMETHOD.
ENDCLASS.
📌查看答案
代码中的问题:
mv_count可见性不当:mv_count被定义在PUBLIC SECTION,外部代码可以随意修改它,破坏了计数器的封装性。应移到PRIVATE SECTION- 设计问题:
mv_count(实例属性)在构造函数中被赋值为当前实例编号,但外部可以随意修改。如果目的是为每个实例分配唯一编号,应该通过公有方法提供只读访问
修正版本:
1 | CLASS lcl_counter DEFINITION. |
题目10 - [分析] 方法参数传递方式选择
请分析以下三种方法签名,讨论它们的适用场景以及哪种方式是推荐的最佳实践。
1
2
3
4
5
6
7
8
9
10
11 " 方式A
METHODS: get_full_name
EXPORTING ev_name TYPE string.
" 方式B
METHODS: get_full_name
CHANGING cv_name TYPE string.
" 方式C
METHODS: get_full_name
RETURNING VALUE(rv_name) TYPE string.
📌查看答案
三种方式的对比分析:
| 特性 | 方式A (EXPORTING) | 方式B (CHANGING) | 方式C (RETURNING) |
|---|---|---|---|
| 语义 | 方法输出结果给调用者 | 方法修改调用者传入的变量 | 方法返回一个值 |
| 调用方式 | 需要先声明接收变量 | 需要先初始化传入变量 | 可直接内联使用 |
| 链式调用 | 不支持 | 不支持 | 支持 |
| 参数数量 | 可有多个 | 可有多个 | 仅限一个 |
推荐:方式C(RETURNING)是最佳实践
理由:
- 函数式风格:支持链式调用和内联表达式
1
2" RETURNING 支持这种写法
lo_person->get_full_name( )->to_upper( ). - 意图清晰:明确表示方法返回一个值,不修改任何已有变量
- 代码简洁:无需预先声明接收变量
1
2
3
4
5
6" RETURNING
DATA(lv_name) = lo_person->get_full_name( ).
" EXPORTING 需要更多代码
DATA: lv_name TYPE string.
lo_person->get_full_name( IMPORTING ev_name = lv_name ).
何时用其他方式:
EXPORTING:方法需要返回多个值时CHANGING:方法需要读取并修改调用者的变量时- 一般规则:返回单个值用
RETURNING,返回多个值用EXPORTING
📌模式总结
| 关键词 | 答案 |
|---|---|
| 类定义结构 | DEFINITION(声明)+ IMPLEMENTATION(实现) |
| 可见性三级 | PUBLIC(所有)> PROTECTED(类+子类)> PRIVATE(仅类本身) |
| 实例 vs 静态 | DATA(每对象一份)vs CLASS-DATA(全类共享) |
| 构造函数 | CONSTRUCTOR自动调用,初始化对象状态 |
| 引用赋值 | 赋值引用不创建新对象,两个引用指向同一实例 |
| 参数传递 | RETURNING推荐(支持链式),EXPORTING用于多返回值 |
| 组件选择器 | -> 实例成员,=> 静态成员 |