Abhijeet Kapgate
Posted onNovember 21, 2012 5 minute read
Activating Generic Object Services Toolbar in SAP Objects
FollowRSS feedLike
66 Likes 139,559 Views 88 Comments
Business Requirement
Many a times there is a business requirement of linking documents, entering notes, sending notes or linking an internet address to various SAP objects. These external attachments can be reference documents, pictures, Email attachments, designs, diagrams or related spreadsheets. To meet this requirement SAP has provided a tool bar called ‘Generic Object services toolbar’ or ‘GOS toolbar’.
What is GOS
The GOS is a toolbar that provides different functions such as adding an attachment, creating a document link, displaying all the attachments etc. The attachments are not generic for that transaction but are specific for a particular SAP object. The GOS toolbar can be activated using a class CL_GOS_MANAGER.
Currently in the system the GOS toolbar is available by default only for certain SAP objects.
For Ex. ME21N. See screen shot below. The GOS toolbar is highlighted.
As shown above, the attachments created in ME21N screen will be linked to a particular purchase order and cannot be seen for any other purchase order in ME22N or ME23N screens.
Services that the GOS toolbar provides
The following list shows all possible object services. Not all object services are available – it depends on objects that are already active. Individual object services can also only be accessed using a sub-menu, so that the symbol is not displayed in the toolbox.
Adding an attachment
Entering a Note with an Object
Sending an Object with a Note
Starting a Workflow for an Object
Linking an Internet Address
Entering a Bar Code
Tracing Events for the Object (Subscription)
Telephony
Displaying Object History
Displaying Workflows for the Object
Displaying Transmissions for an Object
Displaying Relationships
Displaying Attachments
Activating Generic Object Services toolbar
The Class CL_GOS_MANAGER is used for activating the GOS toolbar. We have to create an instance of the class. The instance of the class can be created by calling the constructor method. Also, a variable of type BORIDENT needs to be created for the application business object. The object type and object key is assigned to this variable which is then passed to the instance of the class CL_GOS_MANAGER as shown below. This entire code has to be written either inside a suitable user-exit, enhancement point. If both user-exit and enhancement point are not applicable, implicit enhancement can be created inside the standard of that transaction where GOS has to be activated.
DATA: LR_GOS_MANAGER TYPE REF TO CL_GOS_MANAGER,LS_BORIDENT TYPE BORIDENT.
LS_BORIDENT-OBJTYPE = ‘BUS2081’.
LS_BORIDENT-OBJKEY = ‘12345678902011’.
CREATE OBJECT LR_GOS_MANAGEREXPORTING
IS_OBJECT = LS_BORIDENT
IP_NO_COMMIT = ‘ ‘
EXCEPTIONS
OBJECT_INVALID = 1.
Here the object key is the combination of the SAP fields that are mandatorily required to execute those transactions. This will publish the GOS with the supplied BO instance if it is used in an executable program.
Earlier the Function Module SWU_OBJECT_PUBLISH was used for activating the GOS toolbar which now has become obsolete. The object type and the object key were passed as the import parameters to the function module.
Example
For the material BOM transactions (CS01, CS02, CS03), the GOS tool bar is not provided by standard SAP. See screen shot below.
We will see below how we can activate the GOS toolbar using above class for transactions CS01 / CS02 / CS03.
To activate it we need to do an enhancement in include ‘LCSDIFCD’ inside form OKCODE_BEARBEITEN. For transaction ‘CS03’ material number, plant, BOM usage are the required fields. See screen shot below:
So the object key for above example is combination of values of material number, plant and BOM usage.
How to get the object key
The object key can be found out from the object type. Enter the object type in transaction ‘SWO1’
Click on display.
E.g. If material number is 100000000000000099,
plant is – 1234 and
BOM usage – 5, the object key will be
Object-key = ‘10000000000000009912345’
2. The object type can be found in table TOBJ and also from transaction SWO1.The object type for Material BOM (CS01/02/03) – BUS1082.
3. Leave the IP_NO_COMMIT parameter as blank.
If the parameter IP_NO_COMMIT is set, it means that your application should start ‘COMMIT WORK’ command. That is also the default value.
If the parameter is empty, the object services will call the ‘COMMIT WORK’. In this case, the data passed should be consistent.
When called because the database changes cannot be reversed using ‘ROLLBACK’.
4. The GOS toolbar / Button will now be visible and activated in t-codes CS01, CS02 and CS03 after the enhancement is activated.
5. For Sales order, the service can be activated by setting user parameter.Set parameter SD_SWU_ACTIVE = ‘X’ in the user profile. This will activate the
generic object services for VA01, VA02 and VA03.
Steps to create attachments for a Material BOM
1] Click on the GOS toolbar. Different options will be displayed.
2. Click on ‘Create-> Create attachment’ option.
3. A pop-up window will be opened to find a file or attachment as shown below.
Select the file and click on open.
4. A success message will be displayed in the task bar.
A success message will be displayed at the status bar ‘The attachment was successfully created’.
Viewing the attachments
1] To view the list of attachments, go to attachment list as shown below.
2] The list will be displayed as shown below.
Some transactions where GOS is activated using this class.
Alert Moderator
Assigned tags
ABAP Extensibility
abap
activating gos
enhancements
gos
View more...
Related Blog Posts
How to implement GOS for standard transaction VA01/VA02/VA03
By Former Member, Mar 02, 2017
Object still in upgrade mode. Finish the upgrade first
By Former Member, Sep 26, 2016
Part I: Custom Business Object – UI (Bonus Plan)
By Ulrike Liebherr, Jan 20, 2017
Related Questions
Activating Generic Object services for certain SAP objects
By Former Member, Jun 12, 2012
Service for Object button is not available when program is called by RFC
By Marcin Czarny, Sep 07, 2016
Customizing object services toolbar
By Former Member, Aug 26, 2008
88 Comments
Kapil Changrani
November 22, 2012 at 7:36 am
Concise and Informative.
Like(0)
Reply
Alert Moderator
Former Member
November 22, 2012 at 9:33 am
Nice Document....Thanks
Like(0)
Reply
Alert Moderator
Ashutosh Mishra
December 21, 2012 at 11:05 am
Hi,
I am not able to write the code that you provide in above part in enhancement include "LCSDIFCD" for CS01/CS02/CS03.
Please explain me how i will resolve this Issue.
Thanks
Like(0)
Reply
Alert Moderator
Abhijeet Kapgate Post author
December 21, 2012 at 11:17 am
Hi Ashutosh,
You will have to create implicit enhancement to write the code.
Like(0)
Reply
Alert Moderator
Ashutosh Mishra
December 21, 2012 at 11:06 am
Helpful answer
Like(0)
Reply
Alert Moderator
Ashutosh Mishra
December 21, 2012 at 1:14 pm
Hi Abhijeet,
Thanks for Quick response!!! can you tell how i ll get the value as a dynamic in Object Key.
Like(0)
Reply
Alert Moderator
Abhijeet Kapgate Post author
December 21, 2012 at 1:34 pm
Hi Ashutosh,
If I understand your query correctly, the business object will always be known as to which SAP object needs to be enhanced to have the GOS toolbar and will not be dynamic.For e.g. you will have clear requirement to enhance this particular transaction.Whereas the object key will always be dynamic and its values will be obtained in the standard structures (table,workareas) which get filled run-time inside the includes where you write the code.
Hope this helps.
Thanks.
Like(0)
Reply
Alert Moderator
Ashutosh Mishra
December 21, 2012 at 1:40 pm
Hi Abhijeet,
After doing the Implicit enhancement i did the code in below format then its working for all the material,Plant and BOM Usage.
DATA: LR_GOS_MANAGER TYPE REF TO CL_GOS_MANAGER,IS_BORIDENT TYPE BORIDENT.
data : l_objky(23) type c.
CONCATENATE POMAT-matnr POMARC-werks RC29N-STLAN INTO l_objky.
IS_BORIDENT-OBJTYPE = 'BUS1082'.
IS_BORIDENT-OBJKEY = l_objky.
CREATE OBJECT LR_GOS_MANAGER
EXPORTING
IS_OBJECT = IS_BORIDENT
IP_NO_COMMIT = ' '
EXCEPTIONS
OBJECT_INVALID = 1.
Thanks a lot for your Document.
Like(0)
Reply
Alert Moderator
Ashutosh Mishra
December 27, 2012 at 10:19 am
Hi all,
If you want to activate Store Business Document then you have to pass the objtype as "BUS1080" in place of "BUS1082" in the above code.
Like(0)
Reply
Alert Moderator
Former Member
June 13, 2013 at 9:26 am
Nice and Informative!.. Good One .Useful.
Like(0)
Reply
Alert Moderator
Aditya Bajoria
July 10, 2013 at 8:23 am
Nice document.
I have a requirement to add this toolbar at budgeting trasnactions such as CJ30-CJ38 etc.
Any help??
Like(0)
Reply
Alert Moderator
Abhijeet Kapgate Post author
July 10, 2013 at 11:31 am
Hi Aditya,
Thank you for your query. You can achieve the requirement by following the above post.
If you debug, you will get an include in the PBO for CJ30 where you can add this piece of code thru implicit enhancement.
The include name is - MKBUDF02
Form name - INIT_PROJ_PBO
Click on the 'Enhance' button (Shift + F4). Go to Menu->Edit->Enhancement Operations->Show implicit enhancement options.
A dotted line will appear. Right click->Enhancement implementation->Create
DATA: LR_GOS_MANAGER TYPE REF TO CL_GOS_MANAGER,LS_BORIDENT TYPE BORIDENT.
LS_BORIDENT-OBJTYPE = 'BUS2001'.
CREATE OBJECT LR_GOS_MANAGEREXPORTING
IS_OBJECT = LS_BORIDENT
IP_NO_COMMIT = ' '
EXCEPTIONS
OBJECT_INVALID = 1.
...
以下内容整理自 SAP 官方 ABAP 速查表(主题:ABAP Object Orientation),作为本文的扩展补充资料。
This ABAP cheat sheet provides an overview on selected syntax options and concepts related to ABAP object orientation.
[!NOTE] - The cheat sheet is supported by code snippets and an executable example. They are not suitable as role models for object-oriented design. Their primary focus is on the syntax and functionality. - For more details, refer to the respective topics in the ABAP Keyword Documentation. Find an overview in the topic ABAP Objects - Overview. - The executable examples reflect several points and code snippets covered in the cheat sheet.
Object-oriented programming in ABAP means dealing with classes and objects.
Objects ...
instances of a type. In this context, they are instances of a class. The terms object and instance are used synonymously.
session](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninternal_session_glosry.htm "Glossary Entry") of an ABAP program.
Classes ...
all instances of a class are set up. All instances are created (i.e they are instantiated) based on this template and, thus, have the same setup.
instances of the class vehicle have the same setup. That means they all share the same kind of components like a brand, model and color or the same functionality like the acceleration or braking distance. However, the values of these components are different from instance to instance. For example, one instance is a red sedan of brand A having a certain acceleration; another instance is a black SUV of brand B and so on. You can create an object (or instance respectively) that stands for an actual vehicle which you can work with. You might create any number of objects that are based on such a class - if instantiation is allowed.
of the objects (the data object declarations)
that determine the behavior of an object
You can either create local or global classes:
| Local classes |
|
| Global classes |
|
[!NOTE] - If a class is only used in one ABAP program, creating a local class is enough. However, if you choose to create a global class, you must bear in mind that such a class can be used everywhere. Consider the impact on the users of the global class when you change, for example, the visibility section of a component or you delete it. - Apart from ADT, global classes can also be created in the ABAP Workbench (SE80) or with transactionSE24in classic ABAP.
Basic structure of classes:
CLASS and ended by ENDCLASS.The code snippet shows a basic skeleton of a global class. There are further additions possible for the declaration part.
"Declaration part
CLASS global_class DEFINITION
PUBLIC "Makes the class a global class in the class library.
FINAL "Means that no subclasses can be derived from this class.
CREATE PUBLIC. "This class can be instantiated anywhere it is visible.
... "Here go the declarations for all components and visibility sections.
ENDCLASS.
"Implementation part
CLASS global_class IMPLEMENTATION.
... "Here go the method implementations.
"Only required if you declare methods in the DEFINITION part.
ENDCLASS.The following snippet shows the skeleton of local class declaration.
PUBLIC addition makes a class a global class in the class library. This is not possible for local classes.CREATE .... Note that CREATE PUBLIC is the default, which means that not specifying any CREATE ... addition makes the class implicitly specified with CREATE PUBLIC."Declaration part
CLASS local_class DEFINITION.
... "Here go the declarations for all components and visibility sections.
"You should place the declarations at the beginning of the program.
ENDCLASS.
"Implementation part
CLASS local_class IMPLEMENTATION.
... "Here go the method implementations.
"Only required if you declare methods in the declaration part.
ENDCLASS.This section covers a selection of additions to declare classes. They are also covered in other sections below, e.g. Additions Related to Inheritance and Instantiation. Find more information on the additions in the ABAP Keyword Documentation. The additions assume dealing with global classes, however, many of the additions are also possible for local classes.
| Addition | Notes |
|
|
Creates a global class |
|
|
The class does not allow inheritance. |
|
|
The class is instantiable anywhere. Note that not specifying a |
|
|
The class can only be instantiated in methods of its subclasses, of the class itself, and of its friends. |
|
|
The class can only be instantiated in methods of the class itself or of its friends. Hence, it cannot be instantiated as an inherited component of subclasses. |
|
|
As the name implies, it is used to inherit from a visible superclass. If the addition is not specified, the created class implicitly inherits from the predefined empty, abstract class |
|
|
To define abstract classes. These classes cannot be instantiated. They can contain both abstract methods and non-abstract methods. Abstract methods can only be implemented in subclasses by redefinition. See a simple implementation example here. |
|
|
|
|
|
For ABAP Unit tests. Find more information in the ABAP Unit Tests cheat sheet. |
|
|
To define ABAP behavior pools. Find more information in the ABAP for RAP: Entity Manipulation Language (ABAP EML) cheat sheet. |
|
|
Makes a local class known in a program before the actual class definition. It is typically used in test classes of ABAP Unit. Find more information here. |
PUBLIC addition to the CLASS statement: CLASS zcl_demo_abap DEFINITION PUBLIC ... The following simplified example demonstrates include programs.
🟢 Click to expand for more details
Global class:
zcl_demo_abap) and copy and paste the following code in the Global Class tab in ADT.if_oo_adt_classrun~main implementation contains method calls to this method. It also contains method calls to a method implemented in a local class in the CCIMP include.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
"This method uses types (data type c1 and the local exception class)
"defined in the CCDEF include
METHODS calculate IMPORTING num1 TYPE i
operator TYPE c1
num2 TYPE i
RETURNING VALUE(result) TYPE i
RAISING lcx_wrong_operator.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"The method called has formal parameters using type declarations from the CCDEF include
TRY.
DATA(result1) = calculate( num1 = 10 operator = '+' num2 = 4 ).
out->write( data = result1 name = `result1` ).
CATCH lcx_wrong_operator.
out->write( `Operator not allowed` ).
ENDTRY.
TRY.
DATA(result2) = calculate( num1 = 10 operator = '-' num2 = 4 ).
out->write( data = result2 name = `result2` ).
CATCH lcx_wrong_operator.
out->write( `Operator not allowed` ).
ENDTRY.
TRY.
DATA(result3) = calculate( num1 = 10 operator = '*' num2 = 4 ).
out->write( data = result3 name = `result3` ).
CATCH lcx_wrong_operator.
out->write( `Operator not allowed` ).
ENDTRY.
"Using local class implemented in the CCIMP include
DATA(hi1) = lcl_demo=>say_hello( ).
out->write( data = hi1 name = `hi1` ).
DATA(hi2) = lcl_demo=>say_hello( xco_cp=>sy->user( )->name ).
out->write( data = hi2 name = `hi2` ).
"Test include (CCAU)
"For running the ABAP Unit test, choose CTRL+Shift+F10 in ADT.
"Or you can make a right click in the class code, choose
"'Run As' and '4 ABAP Unit Test'.
ENDMETHOD.
METHOD calculate.
result = SWITCH #( operator
WHEN '+' THEN num1 + num2
WHEN '-' THEN num1 - num2
ELSE THROW lcx_wrong_operator( ) ).
ENDMETHOD.
ENDCLASS.Code snippet for the CCDEF include:
CLASS lcx_wrong_operator DEFINITION INHERITING FROM cx_static_check.
ENDCLASS.
TYPES c1 TYPE c LENGTH 1.Code snippet for the CCIMP include:
CLASS lcl_demo DEFINITION.
PUBLIC SECTION.
CLASS-METHODS: say_hello IMPORTING name TYPE string optional
RETURNING VALUE(hi) type string.
ENDCLASS.
CLASS lcl_demo IMPLEMENTATION.
METHOD say_hello.
hi = |Hallo{ COND #( WHEN name IS SUPPLIED THEN ` ` && name ) }!|.
ENDMETHOD.
ENDCLASS.Code snippet for the test include (CCAU):
CLASS ltc_test DEFINITION DEFERRED.
CLASS zcl_demo_abap DEFINITION LOCAL FRIENDS ltc_test.
CLASS ltc_test DEFINITION FOR TESTING
RISK LEVEL HARMLESS
DURATION SHORT.
PRIVATE SECTION.
METHODS test_calculate FOR TESTING.
ENDCLASS.
CLASS ltc_test IMPLEMENTATION.
METHOD test_calculate.
"Creating an object of the class under test
DATA(ref_cut) = NEW zcl_demo_abap( ).
"Calling method that is to be tested
TRY.
DATA(result1) = ref_cut->calculate( num1 = 10 operator = '+' num2 = 4 ).
CATCH lcx_wrong_operator.
ENDTRY.
TRY.
DATA(result2) = ref_cut->calculate( num1 = 10 operator = '-' num2 = 4 ).
CATCH lcx_wrong_operator.
ENDTRY.
"Assertions
cl_abap_unit_assert=>assert_equals(
act = result1
exp = 14
quit = if_abap_unit_constant=>quit-no ).
cl_abap_unit_assert=>assert_equals(
act = result2
exp = 6
quit = if_abap_unit_constant=>quit-no ).
ENDMETHOD.
ENDCLASS.In the class declaration part, you specify three visibility sections and include class components to define their visibility. These visibility sections serve the purpose of encapsulation in ABAP Objects. For example, you do not want to make certain components publicly available for all users. The visibility sections are as follows:
PUBLIC SECTION. | Components declared in this section can be accessed from within the class and from all users of the class. |
PROTECTED SECTION. | Components declared in this section can be accessed from within the class and subclasses as well as friends. |
PRIVATE SECTION. | Components declared in this section can only be accessed from within the class in which they are declared and its friends. |
Summary:
| Visible for | PUBLIC SECTION | PROTECTED SECTION | PRIVATE SECTION |
|---|---|---|---|
| Same class and its friends | X | X | X |
| Any subclasses | X | X | - |
| Any repository objects | X | - | - |
At least one section must be specified.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
"Here go the components.
PROTECTED SECTION.
"Here go the components.
PRIVATE SECTION.
"Here go the components.
ENDCLASS.
...All components, i. e.
TYPES, DATA, CLASS-DATA, and CONSTANTS for data types and dataobjects),
METHODS and CLASS-METHODS),EVENTS and CLASS-EVENTS) as well asare declared in the declaration part of the class. There, they must be assigned to a visibility section.
Two kinds of components are to be distinguished when, for example, looking at declarations using DATA and CLASS-DATA having a preceding CLASS-:
Components that exist separately for each instance and can only be accessed in instances of a class.
CLASS-):Components that exist only once per class. They do no not exclusively exist for specific instances. They can be addressed using the name of the class.
class (or interface).
attributes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_attribute_glosry.htm "Glossary Entry") (DATA): Determine the state of objects of a class. The data is only valid in the context of an instance. As shown further down, instance attributes can only be accessed via an object reference variable (or interface reference variable).
attributes](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_attribute_glosry.htm "Glossary Entry") (CLASS-DATA): Their content is independent of instances of a class and, thus, valid for all instances. That means that if you change such a static attribute, the change is visible in all instances. As shown further down, static attributes can be accessed by both using an object reference variable (however, this access is not recommended) and using the class name without a prior creation of an instance.
[!NOTE] - You can declare constant data objects that should not be
changed using CONSTANTS statements. You specify the values for the constants (which are also static attributes) when you declare them in the declaration part of a class.
- The addition
READ-ONLY can be used in the public visibility section. Effect:
- Can be read from outside of the class - Cannot be changed from outside - Can only be changed using methods of the class or its subclasses - Note that when creating attributes in the public visibility section, they are globally visible and can therefore be globally used. Note the consequences on the users when changing attributes in the public visibility section (e.g. making an attribute read-only at a later point in time when, for example, other classes use the attribute).
Declaring attributes in visibility sections. In the code snippet below, all attributes are declared in the public section.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
TYPES some_type TYPE c LENGTH 3. "Type declaration
DATA: inst_number TYPE i, "Instance attributes
inst_string TYPE string,
dobj_r_only TYPE c LENGTH 5 READ-ONLY. "Read-only attribute
CLASS-DATA: stat_number TYPE i, "Static attributes
stat_char TYPE c LENGTH 3.
CONSTANTS const_num TYPE i VALUE 123. "Non-changeable constant
PROTECTED SECTION.
"Here go more attributes if needed.
PRIVATE SECTION.
"Here go more attributes if needed.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
... "Here go all method implementations.
ENDCLASS.procedures determining the behavior of the class.
otherwise, change their content.
interface](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenparameter_interface_glosry.htm "Glossary Entry") (also known as signature) with which methods can get values to work with when being called and pass values back to the caller (see the notes on formal and actual parameters below).
methods](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenstatic_method_glosry.htm "Glossary Entry") can only access static attributes of a class and trigger static events. You declare them using CLASS-METHODS statements in a visibility section.
methods](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_method_glosry.htm "Glossary Entry") can access all of the attributes of a class and trigger all events. You declare them using METHODS statements in a visibility section. Note that you must create an instance of a class first before using instance methods. Called within the same class, an instance is not required.
CLASS-METHODS and METHODS can be followed by a colon to list one or more methods, separated by commas, or without a colon to declare a single method.The following code snippet (which anticipates aspects described in the following sections, such as specifying the method signature, constructors etc.) shows multiple method definitions in the public section of a global class. Most of the formal parameters of the demo methods below are defined by just using the parameter name. This means passing by reference (returning parameters require to be passed by value).
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
METHODS: inst_meth1, "instance methods
inst_meth2 IMPORTING a TYPE string,
inst_meth3 IMPORTING b TYPE i
EXPORTING c TYPE i,
inst_meth4 IMPORTING d TYPE string
RETURNING VALUE(e) TYPE string,
"Note that method declarations should be done with care. An example
"as follows may not be advisable, e.g. specifying multiple output
"parameters (both exporting and returning parameters for a method).
"As is valid for all examples in the cheat sheet, the focus is on
"syntax options.
inst_meth5 IMPORTING f TYPE i
EXPORTING g TYPE i
CHANGING h TYPE string
RETURNING VALUE(i) TYPE i
RAISING cx_sy_zerodivide,
constructor IMPORTING j TYPE i. "instance constructor with importing parameter
CLASS-METHODS: stat_meth1, "static methods
stat_meth2 IMPORTING k TYPE i
EXPORTING l TYPE i,
class_constructor, "static constructor
"Options of formal parameter definitions
stat_meth3 IMPORTING VALUE(m) TYPE i, "pass by value
stat_meth4 IMPORTING REFERENCE(n) TYPE i, "pass by reference
stat_meth5 IMPORTING o TYPE i, "same as n; the specification of REFERENCE(...) is optional
stat_meth6 RETURNING VALUE(p) TYPE i, "pass by value once more (note: it's the only option for returning parameters)
"OPTIONAL/DEFAULT additions
stat_meth7 IMPORTING q TYPE i DEFAULT 123
r TYPE i OPTIONAL,
"The examples above use a complete type for
"the parameter specification. Generic types
"are possible.
stat_meth8 IMPORTING s TYPE any "Any data type
t TYPE any table "Any internal table type
u TYPE clike. "Character-like types (c, n, string, d, t and character-like flat structures)
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD inst_meth1.
...
ENDMETHOD.
... "Further method implementations. Note that all declared methods must go here.
ENDCLASS.In the simplest form, methods can have no parameter at all. Apart from that, methods can be defined with the following parameters:
| Addition | Details |
|---|---|
IMPORTING | Defines one or more input parameters to be imported by the method. |
EXPORTING | Defines one or more output parameters to be exported by the method. |
CHANGING | Defines one or more input or output parameters, i. e. that can be both imported and exported. |
RETURNING | For functional methods, i. e. such methods have only one RETURNING parameter that can be defined. As an output parameter like the EXPORTING parameter, RETURNING parameters pass back values (note that the formal parameters of returning parameters must be passed by value as covered below; the parameter must be completely typed). In contrast to EXPORTING for which multiple parameters can be specified, only one RETURNING parameter can be specified in a method. If you only need one output parameter, you can benefit from using a RETURNING parameter by shortening the method call and enabling method chaining. Another big plus is that such functional methods can, for example, be used in expressions. In case of standalone method calls, the returned value can be accessed using the addition RECEIVING. |
RAISING | Used to declare the class-based exceptions that can be propagated from the method to the caller. It can also be specified with the addition RESUMABLE for resumable exceptions. Find more information in the Exceptions and Runtime Errors cheat sheet. |
[!NOTE] - It is advisable to avoid specifying multiple different output parameters (exporting, returning, changing) in a signature to reduce complexity. - Find more information here. - You may find the addition EXCEPTIONS especially in definitions of older classes. They are for non-class-based exceptions. This addition should not be used in ABAP for Cloud Development. See the section Class-Based Exceptions, and the section Classic Exceptions in the Exceptions and Runtime Errors cheat sheet.
type.
fp is the formal parameter that has a complete type: ... meth IMPORTING fp TYPE string ...gen is the formal parameter that has a generic type: ... meth IMPORTING gen TYPE any ...... REFERENCE(param) ...; note that just specifying the parameter name ... param ... - as a shorter syntax - means passing by reference by default) ... VALUE(param) ...The following example (which anticipates aspects described in the following sections, such as calling methods) shows a class with a simple method demonstrating the syntax for formal parameter specifications. Complete types are used.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
"Passing by reference and value
METHODS: meth IMPORTING i_a TYPE i
REFERENCE(i_b) TYPE string
VALUE(i_c) TYPE i
RETURNING VALUE(r_a) TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"The values 1, hello, and 2 are actual parameters supplied when
"the method is called.
DATA(result) = meth( i_a = 1
i_b = `hello`
i_c = 2 ).
ENDMETHOD.
METHOD meth.
... "Method implementation
"Input parameters passed by reference cannot be changed in the method implementation.
"i_a += 1.
"i_b &&= ` world`.
"Input parameters passed by value can be changed in the method implementation.
i_c += 1.
r_a = `ABAP`.
ENDMETHOD.
ENDCLASS.Syntax for completely typing a formal parameter:
TYPE complete_typeTYPE LINE OF complete_typeTYPE REF TO typeLIKE dobjLIKE LINE OF dobjLIKE REF TO dobj[!NOTE] -complete_type: Stands for a non-generic built-in ABAP, ABAP DDIC, ABAP CDS, a public data type from a global class or interface, or a local type declared withTYPES-REF TOtypes as a reference variable. A generic type cannot be specified afterREF TO. A typing withTYPE REF TO dataandTYPE REF TO objectis considered as completely typing a formal parameter. - Enumerated types can also be used to type the formal parameter. - The considerations also apply to the typing of field symbols.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
"Local types and data objects used in the example
TYPES c3 TYPE c LENGTH 3.
TYPES der_type TYPE TABLE FOR CREATE zdemo_abap_rap_ro_m.
DATA int TYPE i.
DATA itab TYPE TABLE OF zdemo_abap_fli_ve WITH EMPTY KEY.
"Various syntax options for completely typing formal parameters
"Note: The example parameters are all specified for passing
"actual parameters by reference.
METHODS: meth IMPORTING
"Non-generic built-in ABAP types
i_a TYPE i
i_b TYPE string
"ABAP DDIC types
i_c TYPE land1 "elementary type
i_d TYPE timestampl "elementary type
i_e TYPE zdemo_abap_fli "structured type based on DDIC database table
i_f TYPE string_hashed_table "table type
"ABAP CDS types (all of the examples are structured types)
i_g TYPE zdemo_abap_fli_ve "CDS view entity
i_h TYPE zdemo_abap_abstract_ent "CDS abstract entity
i_i TYPE zdemo_abap_table_function "CDS table function
"Data types declared in public section of a class
i_j TYPE zcl_demo_abap_dtype_dobj=>t_pub_text_c30 "elementary type
i_k TYPE zcl_demo_abap_amdp=>carr_fli_struc "structured type
i_l TYPE zcl_demo_abap_amdp=>carr_fli_tab "table type
"Data types declared in an interface
i_m TYPE zdemo_abap_get_data_itf=>occ_rate "elementary type
i_n TYPE zdemo_abap_get_data_itf=>carr_tab "table type
"Local types
i_o TYPE c3 "elementary type
i_p TYPE der_type "table type (BDEF derived type)
"Note: Examples such as the following are not allowed type specifications of formal parameters.
"In the following cases, extra (local) type declarations with TYPES are required before the
"method declaration to type the formal parameters.
"i_no1 TYPE c LENGTH 3
"i_no2 TYPE TABLE OF zdemo_abap_fli WITH EMPTY KEY
"Reference types
i_q TYPE REF TO i "Data reference
i_r TYPE REF TO zdemo_abap_carr "Data reference
i_s TYPE REF TO zcl_demo_abap_unit_test "Object reference
i_t TYPE REF TO data "Data reference (considered as complete typing, too)
i_u TYPE REF TO object "Object reference (considered as complete typing, too)
"TYPE LINE OF addition (structured type based on a table type)
i_v TYPE LINE OF zcl_demo_abap_amdp=>carr_fli_tab
i_w TYPE LINE OF der_type
"LIKE addition (types based on existing data objects)
i_x LIKE int "Local data object
i_y LIKE zcl_demo_abap_dtype_dobj=>comma "Constant specified in a class
i_z LIKE zdemo_abap_objects_interface=>stat_str "Data object specified in an interface
"LIKE LINE OF addition (types based on existing internal tables)
i_1 LIKE LINE OF itab "Local internal table
"LIKE REF TO addition (reference types based on existing data object)
i_2 LIKE REF TO int "Local elementary data object
i_3 LIKE REF TO itab "Local internal table
.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Calling methods and providing actual parameters
* meth(
* i_a = 1
* i_b = `hello`
* ... ).
ENDMETHOD.
METHOD meth.
... "Method implementation
ENDMETHOD.
ENDCLASS.Find more information on generic types in the Data Types and Data Objects cheat sheet. The following code snippet anticipates aspects described in the following sections, such as calling methods.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
"Example method demonstrating the generic typing of formal parameters
METHODS: meth IMPORTING
"Any data type
i_data TYPE data
i_any TYPE any
"Character-like types
i_c TYPE c "Text field with a generic length
i_clike TYPE clike "Character-like (c, n, string, d, t, and character-like flat structures)
i_csequence TYPE csequence "Text-like (c, string)
i_n TYPE n "Numeric text with generic length
i_x TYPE x "Byte field with generic length
i_xsequence TYPE xsequence "Byte-like (x, xstring)
"Numeric types
i_decfloat TYPE decfloat "decfloat16 decfloat34
i_numeric TYPE numeric "Numeric (i, int8, p, decfloat16, decfloat34, f, (b, s))
i_p TYPE p "Packed number (generic length and number of decimal places)
"Internal table types
i_any_table TYPE ANY TABLE "Internal table with any table type
i_hashed_table TYPE HASHED TABLE
i_index_table TYPE INDEX TABLE
i_sorted_table TYPE SORTED TABLE
i_standard_table TYPE STANDARD TABLE
i_table TYPE table "Standard table
"Other types
i_simple TYPE simple "Elementary data type including enumerated types and
"structured types with exclusively character-like flat components
.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Structure including various components of specific types
"They represent actual parameters in the method call below
DATA: BEGIN OF s,
c3 TYPE c LENGTH 3,
c10 TYPE c LENGTH 10,
n4 TYPE n LENGTH 4,
str TYPE string,
time TYPE t,
date TYPE d,
dec16 TYPE decfloat16,
dec34 TYPE decfloat34,
int TYPE i,
pl4d2 TYPE p LENGTH 4 DECIMALS 2,
tab_std TYPE STANDARD TABLE OF string WITH EMPTY KEY,
tab_so TYPE SORTED TABLE OF string WITH NON-UNIQUE KEY table_line,
tab_ha TYPE HASHED TABLE OF string WITH UNIQUE KEY table_line,
xl1 TYPE x LENGTH 1,
xstr TYPE xstring,
structure TYPE zdemo_abap_carr, "character-like flat structure
END OF s.
"The following method call specifies various actual parameters for the
"generic formal parameters.
"Note the comments for allowed and not allowed example assignments of
"actual parameters.
meth(
"------------- Any data type -------------
"--- data/any: Allowed (examples) ---
i_data = s-c3
"i_data = s-time
"i_data = s-tab_std
"i_data = s-xstr
i_any = s-c3
"i_any = s-time
"i_any = s-tab_std
"i_any = s-xstr
"------------- Character-like types -------------
"--- c: Allowed (examples) ---
i_c = s-c3
"i_c = s-c10
"--- c: Not allowed (examples) ---
"i_c = s-str
"i_c = s-n4
"--- clike: Allowed (examples) ---
i_clike = s-c3
"i_clike = s-c10
"i_clike = s-str
"i_clike = s-structure
"i_clike = s-time
"i_clike = s-date
"i_clike = s-n4
"--- clike: Not allowed (examples) ---
"i_clike = s-xstr
"i_clike = s-xl1
"i_clike = s-pl4d2
"--- csequence: Allowed (examples) ---
i_csequence = s-c3
"i_csequence = s-c10
"i_csequence = s-str
"--- csequence: Not allowed (examples) ---
"i_csequence = s-time
"i_csequence = s-date
"i_csequence = s-structure
"--- n: Allowed ---
i_n = s-n4
"--- n: Not allowed (examples) ---
"i_n = s-c3
"i_n = s-int
"--- x: Allowed ---
i_x = s-xl1
"--- x: Not allowed (examples) ---
"i_x = s-xstr
"i_x = s-c3
"--- xsequence: Allowed ---
i_xsequence = s-xstr
"i_xsequence = s-xl1
"--- xsequence: Not allowed (examples) ---
"i_xsequence = s-c3
"i_xsequence = s-str
"--- decfloat: Allowed ---
i_decfloat = s-dec16
"i_decfloat = s-dec34
"--- decfloat: Not allowed (examples) ---
"i_decfloat = s-int
"i_decfloat = s-pl4d2
"--- numeric: Allowed (examples) ---
i_numeric = s-int
"i_numeric = s-dec16
"i_numeric = s-dec34
"i_numeric = s-pl4d2
"--- numeric: Not allowed (examples) ---
"i_numeric = s-n4
"i_numeric = s-date
"--- p: Allowed ---
i_p = s-pl4d2
"--- p: Not allowed (examples) ---
"i_p = s-dec16
"i_p = s-dec34
"--- any table: Allowed ---
i_any_table = s-tab_std
"i_any_table = s-tab_ha
"i_any_table = s-tab_so
"--- any table: Not allowed (examples) ---
"i_any_table = s-structure
"i_any_table = s-c3
"--- hashed table: Allowed ---
i_hashed_table = s-tab_ha
"--- hashed table: Not allowed ---
"i_hashed_table = s-tab_std
"i_hashed_table = s-tab_so
"--- index table: Allowed ---
i_index_table = s-tab_std
"i_index_table = s-tab_so
"--- index table: Not allowed ---
"i_index_table = s-tab_ha
"--- sorted table: Allowed ---
i_sorted_table = s-tab_so
"--- sorted table: Not allowed ---
"i_sorted_table = s-tab_std
"i_sorted_table = s-tab_ha
"--- standard table/table: Allowed ---
i_standard_table = s-tab_std
i_table = s-tab_std
"--- standard table/table: Not allowed ---
"i_standard_table = s-tab_so
"i_standard_table = s-tab_ha
"i_table = s-tab_so
"i_table = s-tab_ha
"--- simple: Allowed (examples) ---
i_simple = s-structure
"i_simple = s-c3
"i_simple = s-n4
"i_simple = s-int
"i_simple = s-pl4d2
"i_simple = s-xstr
"i_simple = s-str
"--- simple: Not allowed (examples) ---
"i_simple = s-tab_ha
"i_simple = s-tab_so
).
ENDMETHOD.
METHOD meth.
... "Method implementation
ENDMETHOD.
ENDCLASS.IMPORTING and CHANGING can be defined as optional using the OPTIONAL and DEFAULT additions: OPTIONAL: It is then not mandatory to pass an actualparameter.
DEFAULT: Also makes the passing of an actual parameter optional. However, when using this addition, as the name implies, a default value is set.IS SUPPLIED. See the example further down.The following example (which anticipates aspects described in the following sections, such as calling methods) includes three methods that specify optional parameters. The methods are called with and without providing actual parameters. The method implementations include the use of the predicate expression IS SUPPLIED with IF statements and the COND operator. The console output of the example, run with F9, is as follows:
meth1_result_a
The parameter is not supplied. Initial value: "0".
meth1_result_b
The parameter is supplied. Value: "2".
meth2_result_a
The parameter is not supplied. Default value: "1".
meth2_result_b
The parameter is supplied. Value: "3".
meth3_result_b
num1: "4" / num2 (is not supplied; initial value): "0" / num3 (is not supplied; default value): "1"
meth3_result_c
num1: "5" / num2 (is supplied): "6" / num3 (is not supplied; default value): "1"
meth3_result_d
num1: "7" / num2 (is not supplied; initial value): "0" / num3 (is supplied): "8" CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS meth1 IMPORTING num TYPE i OPTIONAL
RETURNING VALUE(str) TYPE string.
METHODS meth2 IMPORTING num TYPE i DEFAULT 1
RETURNING VALUE(str) TYPE string.
METHODS meth3 IMPORTING num1 TYPE i
num2 TYPE i OPTIONAL
num3 TYPE i DEFAULT 1
RETURNING VALUE(str) TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(meth1_result_a) = meth1( ).
DATA(meth1_result_b) = meth1( 2 ).
DATA(meth2_result_a) = meth2( ).
DATA(meth2_result_b) = meth2( 3 ).
"The commented out statement is not possible as there is one
"non-optional parameter.
"DATA(meth3_result_a) = meth3( ).
DATA(meth3_result_b) = meth3( 4 ).
DATA(meth3_result_c) = meth3( num1 = 5 num2 = 6 ).
DATA(meth3_result_d) = meth3( num1 = 7 num3 = 8 ).
out->write( data = meth1_result_a name = `meth1_result_a` ).
out->write( data = meth1_result_b name = `meth1_result_b` ).
out->write( data = meth2_result_a name = `meth2_result_a` ).
out->write( data = meth2_result_b name = `meth2_result_b` ).
out->write( data = meth3_result_b name = `meth3_result_b` ).
out->write( data = meth3_result_c name = `meth3_result_c` ).
out->write( data = meth3_result_d name = `meth3_result_d` ).
ENDMETHOD.
METHOD meth1.
IF num IS SUPPLIED.
str = |The parameter is supplied. Value: "{ num }".|.
ELSE.
str = |The parameter is not supplied. Initial value: "{ num }".|.
ENDIF.
ENDMETHOD.
METHOD meth2.
str = COND #( WHEN num IS SUPPLIED THEN |The parameter is supplied. Value: "{ num }".|
ELSE |The parameter is not supplied. Default value: "{ num }".| ).
ENDMETHOD.
METHOD meth3.
str = |num1: "{ num1 }" / |.
str &&= |{ COND #( WHEN num2 IS SUPPLIED THEN |num2 (is supplied): "{ num2 }"|
ELSE |num2 (is not supplied; initial value): "{ num2 }"| ) } / |.
str &&= |{ COND #( WHEN num3 IS SUPPLIED THEN |num3 (is supplied): "{ num3 }"|
ELSE |num3 (is not supplied; default value): "{ num3 }"| ) } |.
ENDMETHOD.
ENDCLASS.PREFERRED PARAMETER addition, you can flag an input parameter from the list as preferred.OPTIONAL or DEFAULT).OPTIONAL or DEFAULT, or a warning will be displayed.The following example (which anticipates aspects described in the following sections, such as calling methods) shows a simple method with input parameters of type i (an addition is performed using the actual parameter values), where one parameter is preferred. The IS SUPPLIED addition in COND statements checks whether parameters are supplied. The final output shows the preferred parameter assigned automatically when the formal parameter is not specified explicitly. To try the example out, create a demo class named zcl_demo_abap and paste the code into it. After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console. The example should display the following:
IS SUPPLIED: num1 "X", num2 "X", num3 "X" / Addition result "9"
IS SUPPLIED: num1 "X", num2 "X", num3 "" / Addition result "7"
IS SUPPLIED: num1 "", num2 "X", num3 "X" / Addition result "6"
IS SUPPLIED: num1 "X", num2 "", num3 "X" / Addition result "6"
IS SUPPLIED: num1 "", num2 "X", num3 "" / Addition result "4"
IS SUPPLIED: num1 "", num2 "", num3 "X" / Addition result "3"
IS SUPPLIED: num1 "", num2 "", num3 "" / Addition result "1"
IS SUPPLIED: num1 "X", num2 "", num3 "" / Addition result "4"Example code:
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
CLASS-METHODS meth
IMPORTING num1 TYPE i OPTIONAL
num2 TYPE i OPTIONAL
num3 TYPE i DEFAULT 1
PREFERRED PARAMETER num1
RETURNING VALUE(text) TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(text1) = meth( num1 = 3 num2 = 3 num3 = 3 ).
out->write( text1 ).
DATA(text2) = meth( num1 = 3 num2 = 3 ).
out->write( text2 ).
DATA(text3) = meth( num2 = 3 num3 = 3 ).
out->write( text3 ).
DATA(text4) = meth( num1 = 3 num3 = 3 ).
out->write( text4 ).
DATA(text5) = meth( num2 = 3 ).
out->write( text5 ).
DATA(text6) = meth( num3 = 3 ).
out->write( text6 ).
DATA(text7) = meth( ).
out->write( text7 ).
"Not specifying the name of the formal parameter. The
"actual parameter is assigned to the preferred input
"parameter.
DATA(text8) = meth( 3 ).
out->write( text8 ).
ENDMETHOD.
METHOD meth.
DATA(addition) = num1 + num2 + num3.
text = |IS SUPPLIED: num1 "{ COND #( WHEN num1 IS SUPPLIED THEN 'X' ELSE '' ) }", | &&
|num2 "{ COND #( WHEN num2 IS SUPPLIED THEN 'X' ELSE '' ) }", | &&
|num3 "{ COND #( WHEN num3 IS SUPPLIED THEN 'X' ELSE '' ) }" / | &&
|Addition result "{ addition }"|.
ENDMETHOD.
ENDCLASS.are special methods that are usually used for setting a defined initial value for attributes of the class or its objects.
constructor](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abeninstance_constructor_glosry.htm "Glossary Entry") and one static constructor.
class_constructor as part of aCLASS-METHODS statement in the public visibility section.
the first time in an internal session, i. e. when, for example, an instance of a class is created or a component is used. Note: If it is not explicitly declared and implemented, it is merely an empty method.
constructor as part of aMETHODS statement. In case of global classes, it can only be declared in the public visibility section.
instantiated and an instance is created.
IMPORTING parameters and raise exceptions.The following example (which anticipates aspects described in the following sections, such as creating instances of classes) demonstrates static and instance constructors. To try the example out, create a demo class named zcl_demo_abap and paste the code into it. After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console.
Notes:
static_timestamp value and stat_constr_call_count value, which remains 1. instance_timestamp attribute shows different timestamps for each created instance. instance_constr_call_count increases with each instance. Note that running the class with F9 in ADT also calls the instance and static constructors. Thus, the final instance_constr_call_count totals the number of DO loop passes plus 1, starting with 2 for inst1 instead of 1.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS constructor IMPORTING text TYPE string OPTIONAL.
CLASS-METHODS class_constructor.
PROTECTED SECTION.
PRIVATE SECTION.
DATA instance_timestamp TYPE utclong.
CLASS-DATA static_timestamp TYPE utclong.
DATA instance_name TYPE string.
CLASS-DATA stat_constr_call_count TYPE i.
CLASS-DATA instance_constr_call_count TYPE i.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA itab TYPE string_table.
DO 5 TIMES.
DATA(inst) = NEW zcl_demo_abap( |inst{ sy-index }| ).
APPEND |-------------- Instance "{ inst->instance_name }" --------------| TO itab.
APPEND |instance_timestamp: { inst->instance_timestamp }| TO itab.
APPEND |static_timestamp: { inst->static_timestamp }| TO itab.
APPEND |instance_constr_call_count: { inst->instance_constr_call_count }| TO itab.
APPEND |stat_constr_call_count: { inst->stat_constr_call_count }| TO itab.
APPEND INITIAL LINE TO itab.
ENDDO.
out->write( itab ).
ENDMETHOD.
METHOD class_constructor.
static_timestamp = utclong_current( ).
stat_constr_call_count += 1.
ENDMETHOD.
METHOD constructor.
instance_timestamp = utclong_current( ).
instance_constr_call_count += 1.
IF text IS SUPPLIED AND text IS NOT INITIAL.
instance_name = text.
ENDIF.
ENDMETHOD.
ENDCLASS.those objects.
"Declaring object reference variables
DATA: ref1 TYPE REF TO local_class,
ref2 TYPE REF TO global_class,
ref3 LIKE ref1.NEW, you can create objects of a class (and anonymous data objects, too, that are not dealt with here). As a result, you get a reference variable that points to the created object.
parentheses:
NEW, the type, i. e. the class, must be specified. The # character - instead of the class name -means that the type (TYPE REF TO ...) can be derived from the context (in this case from the type of the reference variable). You can also omit the explicit declaration of a reference variable by declaring a new reference variable inline, for example, using DATA. In this case, the name of the class must be placed after NEW and before the first parenthesis.
passed to the instance constructor of an object. However, non-optional input parameters of the instance constructor of the instantiated class must be filled. No parameters are passed for a class without an explicitly declared instance constructor. See more information: here.
basically replaces the syntax CREATE OBJECT you might stumble on. However, CREATE OBJECT statements are still required (i.e. they are the only option, NEW is not possible for them) for creating objects dynamically. For more information, see the Dynamic Programming cheat sheet.
"Declaring object reference variable
DATA: ref1 TYPE REF TO some_class.
"Creating objects
ref1 = NEW #( ). "Type derived from already declared ref1
DATA(ref2) = NEW some_class( ). "Reference variable declared inline, explicit type
"(class) specification
"The assumption is that this class has no mandatory importing parameters for the
"instance constructor. If a class has, actual parameters must be provided.
DATA(ref_mand_param) = NEW another_class( ip1 = ... ip2 = ... ).
"Older syntax, replaced by NEW operator
"However, CREATE OBJECT is required in dynamic object creation.
CREATE OBJECT ref3. "Type derived from already declared ref3
CREATE OBJECT ref4 TYPE some_class. "Corresponds to the result of the expression aboveThis section covers some aspects of working with reference variables. Find a copyable example demonstrating the aspects in the next section.
Assigning Reference Variables
To assign or copy reference variables, use the assignment operator =. In the example below, both object reference variables have the same type. Note the concepts of polymorphism, upcasts and downcasts when assigning reference variables covered further down.
DATA: ref1 TYPE REF TO some_class,
ref2 TYPE REF TO some_class.
ref1 = NEW #( ).
"Assigning existing reference
ref2 = ref1.Overwriting reference variables: An object reference is overwritten when a new object is created with a reference variable already pointing to an instance.
DATA ref TYPE REF TO some_class.
"Creating a new object
"The example assumes there is a mandatory importing parameter for the
"instance constructor.
ref = NEW #( 1 ).
"Creating another object using the same object reference variable
"The existing reference is overwritten.
ref = NEW #( 1 ).Retaining object references:
... TYPE TABLE OF REF TO ....DATA: ref TYPE REF TO some_class,
itab TYPE TABLE OF REF TO some_class.
DO 3 TIMES.
ref = NEW #( ).
itab = VALUE #( BASE itab ( ref ) ). "Adding the reference to itab
ENDDO.Clearing object references: You can use CLEAR statements to explicitly clear a reference variable.
CLEAR ref.[!NOTE] Objects use up space in the memory and should therefore be
cleared if they are no longer needed. However, the garbage collector is called periodically and automatically by the ABAP runtime framework and clears all objects without any reference.
the object component selector -> via a reference variable.
selector](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenclass_component_select_glosry.htm "Glossary Entry") => via the class name. Static attributes can but should not be addressed via a reference variable.
"Accessing instance attribute via an object reference variable
... ref->some_attribute ...
"Accessing static attributes via the class name
... some_class=>static_attribute ...
"Without the class name only within the class itself
... static_attribute ...
"Type and data object declarations
TYPES some_type LIKE some_class=>some_static_attribute.
DATA dobj1 TYPE some_class=>some_type.
DATA dobj2 LIKE some_class=>some_static_attribute.The following executable example addresses aspects of this section and the previous one:
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS constructor IMPORTING ts TYPE utclong OPTIONAL.
DATA timestamp TYPE utclong.
DATA instance_number TYPE i.
CLASS-DATA static_number TYPE i.
TYPES chars TYPE c LENGTH 4.
CONSTANTS text TYPE chars VALUE `ABAP`.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-METHODS test_static_method.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA oref TYPE REF TO zcl_demo_abap.
DATA oref2 TYPE REF TO zcl_demo_abap.
*&---------------------------------------------------------------------*
*& Assigning object reference variables
*&---------------------------------------------------------------------*
oref = NEW #( utclong_current( ) ).
"Accessing instance attribute
DATA(ts1) = oref->timestamp.
out->write( data = ts1 name = `ts1` ).
"Assigning reference to existing reference variable
oref2 = oref.
DATA(ts2) = oref2->timestamp.
out->write( data = ts2 name = `ts2` ).
*&---------------------------------------------------------------------*
*& Overwriting a reference variable
*&---------------------------------------------------------------------*
oref = NEW #( utclong_current( ) ).
DATA(ts3) = oref->timestamp.
out->write( data = ts3 name = `ts3` ).
*&---------------------------------------------------------------------*
*& Retaining object references
*&---------------------------------------------------------------------*
DATA oref_tab TYPE TABLE OF REF TO zcl_demo_abap.
DO 3 TIMES.
oref = NEW #( utclong_current( ) ).
oref->instance_number = sy-index.
oref->static_number = sy-index.
oref_tab = VALUE #( BASE oref_tab ( oref ) ).
ENDDO.
out->write( data = oref_tab name = `oref_tab` ).
*&---------------------------------------------------------------------*
*& Clearing object references
*&---------------------------------------------------------------------*
DATA oref_generic TYPE REF TO object.
oref_generic = NEW zcl_demo_abap( utclong_current( ) ).
IF oref_generic IS INITIAL.
out->write( `oref_generic is initial` ).
ELSE.
out->write( `oref_generic is not initial` ).
ENDIF.
IF oref_generic IS INSTANCE OF zcl_demo_abap.
out->write( `oref_generic is an instance of zcl_demo_abap` ).
ELSE.
out->write( `oref_generic is not an instance of zcl_demo_abap` ).
ENDIF.
CLEAR oref_generic.
IF oref_generic IS INITIAL.
out->write( `oref_generic is initial` ).
ELSE.
out->write( `oref_generic is not initial` ).
ENDIF.
IF oref_generic IS INSTANCE OF zcl_demo_abap.
out->write( `oref_generic is an instance of zcl_demo_abap` ).
ELSE.
out->write( `oref_generic is not an instance of zcl_demo_abap` ).
ENDIF.
*&---------------------------------------------------------------------*
*& Accessing class attributes
*&---------------------------------------------------------------------*
"Accessing instance attribute via an object reference variable
oref = NEW #( utclong_current( ) ).
"Read access
DATA(ts4) = oref->timestamp.
"Write access
oref->instance_number = 123.
"Accessing static attributes via the class name
"Write access
zcl_demo_abap=>static_number = 456.
"Read access
DATA(static_attr_access) = zcl_demo_abap=>static_number.
"Read access (constant)
DATA(const_value) = zcl_demo_abap=>text.
"Accessing static attributes within the class without specifying the class name
"See the test_static_method method for restrictions regarding instance attributes.
"Write access
static_number = 789.
"Read access
static_attr_access = static_number.
"Read access (constant)
const_value = text.
"Type and data object declarations based on class attributes
TYPES type1 TYPE zcl_demo_abap=>chars.
TYPES type2 LIKE zcl_demo_abap=>static_number.
TYPES type3 LIKE zcl_demo_abap=>text.
DATA dobj1 TYPE zcl_demo_abap=>chars.
DATA dobj2 LIKE zcl_demo_abap=>static_number.
DATA dobj3 LIKE zcl_demo_abap=>text.
"Without class name specification within the class itself
TYPES type4 TYPE chars.
TYPES type5 LIKE static_number.
TYPES type6 LIKE text.
DATA dobj4 TYPE chars.
DATA dobj5 LIKE static_number.
DATA dobj6 LIKE text.
"Using instance attributes
"Note: You can access static attributes via object reference variables.
"However, it is advisable to access static attributes as shown above.
DATA(oref3) = NEW zcl_demo_abap( utclong_current( ) ).
TYPES type7 TYPE oref3->chars.
TYPES type8 LIKE oref3->instance_number.
DATA dobj7 TYPE oref3->chars.
DATA dobj8 LIKE oref3->timestamp.
ENDMETHOD.
METHOD constructor.
timestamp = ts.
ENDMETHOD.
METHOD test_static_method.
"Accessing static attributes
zcl_demo_abap=>static_number = 987.
"Read access
DATA(static_attr_access) = zcl_demo_abap=>static_number.
"Read access (constant)
DATA(const_value) = zcl_demo_abap=>text.
"Accessing attributes within the class without specifying the class name
"Write access
static_number = 654.
"Read access
static_attr_access = static_number.
"Read access (constant)
const_value = text.
"Access to instance attributes in static methods like above is not possible
DATA inst_attr_access TYPE utclong.
"inst_attr_access = timestamp.
"Instance attribute access via object reference variable
DATA(oref) = NEW zcl_demo_abap( utclong_current( ) ).
inst_attr_access = oref->timestamp.
ENDMETHOD.
ENDCLASS.methods are called using -> via a reference variable.
methods are called using => via the class name. When used within the class in which it is declared, the static method can also be called without class_name=>....
oref->some_static_method( ).).CALL METHODstatements. It is recommended to use the new syntax in new developments. Note that CALL METHOD statements are still required in the context of dynamic programming. Therefore, CALL METHOD statements should be reserved for dynamic method calls.
EXPORTING. For methods with exporting parameters, you can or must use IMPORTING before the parameters and their assignments.Examples for instance method calls and static method calls:
"Calling instance methods via reference variable;
"within the parentheses, the parameters must be specified and assigned - if required
ref->inst_meth( ... ).
"Calling static methods via/without the class name
class_name=>stat_meth( ... ).
"Only within the program in which it is declared.
stat_meth( ... ).
"Calling (static) method having no parameter
class_name=>stat_meth( ).
"Calling (static) methods having a single importing parameter:
"Note that in the method call, the caller exports values to the
"method having importing parameters defined; hence, the addition
"EXPORTING is relevant for the caller. The following three method calls are the same
"Explicit use of EXPORTING.
class_name=>meth( EXPORTING a = b ).
"Only importing parameters in the method signature: explicit EXPORTING not needed
class_name=>meth( a = b ).
"If only a single value must be passed:
"the formal parameter name (a) and EXPORTING not needed
stat_meth( b ).
"Calling (static) methods having importing/exporting parameters
"Parameters must be specified if they are not marked as optional
class_name=>meth( EXPORTING a = b c = d "a/c: importing parameters in the method signature
IMPORTING e = f ). "e: exporting parameter in the method signature
"To store the value of the parameter, you may also declare it inline.
class_name=>meth( EXPORTING a = b c = d
IMPORTING e = DATA(z) ).
"Calling (static) methods having a changing parameter;
"should be reserved for changing an existing local variable and value
DATA h TYPE i VALUE 123.
class_name=>meth( CHANGING g = h ).
"Calling (static) methods having a returning parameter.
"Basically, they do the same as methods with exporting parameters
"but they are way more versatile, and you can save lines of code.
"They do not need temporary variables.
"In the example, the return value is stored in a variable declared inline.
"i and k are importing parameters
DATA(result) = class_name=>meth( i = j k = l ).
"They can be used with other statements, e. g. logical expressions.
"In the example below, the assumption is that the returning parameter is of type i.
IF class_name=>meth( i = j k = l ) > 100.
...
ENDIF.
"They enable method chaining.
"The example shows a method to create random integer values.
"The methods have a returning parameter.
DATA(random_no) = cl_abap_random_int=>create( )->get_next( ).
"RECEIVING parameter: Available in methods defined with a returning parameter;
"used in standalone method calls only.
"In the snippet, m is the returning parameter; n stores the result.
class_name=>meth( EXPORTING i = j k = l RECEIVING m = DATA(n) ).🟢 Click to expand for more information and example code
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
CLASS-METHODS meth1 IMPORTING i_str TYPE string
i_tab TYPE string_table OPTIONAL
EXPORTING e_dec TYPE decfloat34
e_tab TYPE string_table
RETURNING VALUE(r_int) TYPE i.
CLASS-METHODS meth2 RETURNING VALUE(r_tab) TYPE string_table.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Note: Calling the method in the same class means specifying 'zcl_demo_abap=>' is optional here.
"Standalone method call
"Specifying target data objects for all output parameters
"Inline declarations are handy because you can create an
"appropriately typed data object in place. No need to
"create an extra variable, check on the type etc.
zcl_demo_abap=>meth1(
EXPORTING
i_str = `ABAP`
IMPORTING
e_dec = DATA(a)
e_tab = DATA(b)
RECEIVING
r_int = DATA(c)
).
"Functional method call
"The target data object of the returning parameter is specified on the left side of an assignment.
"Note: In this case, you cannot specify inline declarations for the exporting parameters.
DATA e TYPE decfloat34.
DATA f TYPE string_table.
DATA(g) = zcl_demo_abap=>meth1(
EXPORTING
i_str = `ABAP`
IMPORTING
"e_dec = DATA(h)
"e_tab = DATA(i)
e_dec = e
e_tab = f
).
"Benefits of returning parameters: They can, for example, be used in expressions
"The following snippets show a selection (and ignore the available exporting
"parameters).
CASE zcl_demo_abap=>meth1( i_str = `ABAP` ).
WHEN 0. ...
WHEN 1. ...
WHEN OTHERS. ...
ENDCASE.
IF zcl_demo_abap=>meth1( i_str = `ABAP` ) > 5.
...
ELSE.
...
ENDIF.
"IF used with a predicative method call
"The result of the relational expression is true if the result of the functional
"method call is not initial and false if it is initial. The data type of the result
"of the functional meth1od call, i. e. the return value of the called functional method,
"is arbitrary. A check is made for the type-dependent initial value.
IF zcl_demo_abap=>meth1( i_str = `ABAP` ).
...
ELSE.
...
ENDIF.
DO zcl_demo_abap=>meth1( i_str = `ABAP` ) TIMES.
...
ENDDO.
"Method call result as actual parameter
DATA(j) = zcl_demo_abap=>meth1( i_str = `ABAP` i_tab = zcl_demo_abap=>meth2( ) ).
"Examples of returning parameters typed with a table type
LOOP AT zcl_demo_abap=>meth2( ) INTO DATA(wa1).
...
ENDLOOP.
READ TABLE zcl_demo_abap=>meth2( ) INTO DATA(wa2) INDEX 1.
ENDMETHOD.
METHOD meth1.
... "Method implementation
ENDMETHOD.
METHOD meth2.
... "Method implementation
ENDMETHOD.
ENDCLASS.RETURN statements immediately terminate the current processing block. Usually, the statement is intended for leaving processing blocks early. RETURN. EXIT and CHECK statements might also be used for exiting procedures. However, their use inside loops is recommended. According to the guidelines (F1 docu for standard ABAP), RETURN is the recommendation.RETURN statement can also be specified with an expression. In doing so, the following statement res = some_expr.
RETURN.can also be specified as follows:
RETURN some_expr.In the following examples, the expression result is passed to the returning parameter without naming it explicitly. As an expression, you can specify a constructor expression (and using type inference with # means using the type of the returning parameter).
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC.
PUBLIC SECTION.
INTERFACES: if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
CLASS-METHODS multiply
IMPORTING num1 TYPE i
num2 TYPE i
RETURNING VALUE(result) TYPE i.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(res1) = multiply( num1 = 2 num2 = 3 ).
DATA(res2) = multiply( num1 = 10 num2 = 10 ).
DATA(res3) = multiply( num1 = 99999999 num2 = 99999999 ).
out->write( res1 ). "6
out->write( res2 ). "100
out->write( res3 ). "0
ENDMETHOD.
METHOD multiply.
TRY.
"result = num1 * num2.
RETURN num1 * num2.
CATCH cx_sy_arithmetic_error.
"The following statement is actually not needed in the example, but used nevertheless
"to showcase the specification of a constructor expression after RETURN.
RETURN VALUE #( ).
ENDTRY.
ENDMETHOD.
ENDCLASS.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS add IMPORTING num1 TYPE i
num2 TYPE i
RETURNING VALUE(result) TYPE i.
METHODS subtract IMPORTING num1 TYPE i
num2 TYPE i
RETURNING VALUE(result) TYPE i.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(result_add) = add( num1 = 10 num2 = 20 ).
out->write( result_add ).
DATA(result_subtract) = subtract( num1 = 10 num2 = 20 ).
out->write( result_subtract ).
ENDMETHOD.
METHOD add.
result = num1 + num2.
ENDMETHOD.
METHOD subtract.
RETURN num1 - num2.
ENDMETHOD.
ENDCLASS.When implementing instance methods, you can optionally make use of the implicitly available object reference variable me which is always available at runtime and points to the respective object itself. You can use it, for example, to refer to components of the instance of a particular class:
... some_method( ... ) ...
... me->some_method( ... ) ...You can also address the entire object, which is illustrated in the example of section Method Chaining and Chained Attribute Access. The following code snippet declares a local data object in a method. It has the same name as a data object declared in the private visibility section. me is used to access the non-local data object.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
DATA str TYPE string.
METHODS meth RETURNING VALUE(text) TYPE string.
METHODS pass_me_ref RETURNING VALUE(oref) TYPE REF TO zcl_demo_abap.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
str = `AP`.
DATA(text) = meth( ).
out->write( text ). "ABAP
str = `Hello`.
DATA(oref) = pass_me_ref( ).
out->write( oref->str ).
str = `World`.
oref = pass_me_ref( ).
out->write( oref->str ).
ENDMETHOD.
METHOD meth.
"Declaring a local data object having the same
"name as a data object declared in a visibility section
DATA str TYPE string VALUE `AB`.
"Addressing locally declared data object
DATA(local_string) = str.
"Addressing data object declared in private visibility section
DATA(other_string) = me->str.
text = local_string && other_string.
ENDMETHOD.
METHOD pass_me_ref.
"Adressing the object using the self-reference me
oref = me.
ENDMETHOD.
ENDCLASS.RETURNING) at appropriate read positions. me. ->. NEW) come in handy. The example class below shows functional method calls (i.e. the return value of the method is used as an ABAP operand), and a standalone statement.The following example illustrates method chaining. Find a self-contained example class further down.
"The following class creates random integers. Find more information in the
"class documentation.
"Both methods have returning parameters specified.
DATA(some_int1) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 10 )->get_next( ).
"Getting to the result as above - not using method chaining and inline declarations.
DATA some_int2 TYPE i.
DATA dref TYPE REF TO cl_abap_random_int.
dref = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 10 ).
some_int2 = dref->get_next( ).
"Using the RECEIVING parameter in a standalone method call
DATA some_int3 TYPE i.
dref->get_next( RECEIVING value = some_int3 ).
"IF statement that uses the return value in a read position
IF cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 10 )->get_next( ) < 5.
... "The random number is lower than 5.
ELSE.
... "The random number is equal or greater than 5.
ENDIF.
"Examples using classes of the XCO library (see more information in the
"ABAP for Cloud Development and Released ABAP Classes cheat sheets), in which
"multiple chained method calls can be specified. Each of the methods
"has a returning parameter specified.
"In the following example, 1 hour is added to the current time.
DATA(add1hour) = xco_cp=>sy->time( xco_cp_time=>time_zone->user )->add( iv_hour = 1 )->as( xco_cp_time=>format->iso_8601_extended )->value.
"In the following example, a string is converted to xstring using a codepage
DATA(xstr) = xco_cp=>string( `Some string` )->as_xstring( xco_cp_character=>code_page->utf_8 )->value.
"In the following example, JSON data is created. First, a JSON data builder
"is created. Then, using different methods, JSON data is added. Finally,
"the JSON data is turned to a string.
DATA(json) = xco_cp_json=>data->builder( )->begin_object(
)->add_member( 'CarrierId' )->add_string( 'DL'
)->add_member( 'ConnectionId' )->add_string( '1984'
)->add_member( 'CityFrom' )->add_string( 'San Francisco'
)->add_member( 'CityTo' )->add_string( 'New York'
)->end_object( )->get_data( )->to_string( ).Self-contained example class demonstrating chained method calls with a functional method call and a standalone statement:
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
METHODS add_text IMPORTING str TYPE string
RETURNING VALUE(ref) TYPE REF TO zcl_demo_abap.
METHODS add_space RETURNING VALUE(ref) TYPE REF TO zcl_demo_abap.
METHODS add_period RETURNING VALUE(ref) TYPE REF TO zcl_demo_abap.
METHODS return_text RETURNING VALUE(str) TYPE string.
METHODS display_text IMPORTING cl_run_ref TYPE REF TO if_oo_adt_classrun_out.
DATA text TYPE string.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
*&---------------------------------------------------------------------*
*& Method chaining with a functional method call
*&---------------------------------------------------------------------*
"Hallo NAME. This is an example of method chaining.
DATA(text1) = NEW zcl_demo_abap(
)->add_text( `Hallo`
)->add_space(
)->add_text( xco_cp=>sy->user( )->name
)->add_period(
)->add_space(
)->add_text( `This`
)->add_space(
)->add_text( `is`
)->add_space(
)->add_text( `an`
)->add_space(
)->add_text( `example`
)->add_space(
)->add_text( `of`
)->add_space(
)->add_text( `method`
)->add_space(
)->add_text( `chaining`
)->add_period(
)->return_text( ).
out->write( text1 ).
"The following example chained method call includes a chained attribute
"access at the end so that the target variable contains the content of
"the attribute.
"Example result: Today is 2025-03-05. It's 14:30:38. Have a nice day.
DATA(text2) = NEW zcl_demo_abap(
)->add_text( `Today`
)->add_space(
)->add_text( `is`
)->add_space(
)->add_text( xco_cp=>sy->date( )->as( xco_cp_time=>format->iso_8601_extended )->value
)->add_period(
)->add_space(
)->add_text( `It's`
)->add_space(
)->add_text( xco_cp=>sy->time( xco_cp_time=>time_zone->user
)->as( xco_cp_time=>format->iso_8601_extended
)->value
)->add_period(
)->add_space(
)->add_text( `Have`
)->add_space(
)->add_text( `a`
)->add_space(
)->add_text( `nice`
)->add_space(
)->add_text( `day`
)->add_period(
)->text.
out->write( text2 ).
*&---------------------------------------------------------------------*
*& Method chaining with a standalone statement
*&---------------------------------------------------------------------*
"In the example, the final method call in the chain receives
"the classrun instance available in the implementation of the
"if_oo_adt_classrun~main method. The method implementation
"includes the writing to the console.
"Console output: Lorem ipsum dolor sit amet
NEW zcl_demo_abap( )->add_text( `Lorem`
)->add_space(
)->add_text( `ipsum`
)->add_space(
)->add_text( `dolor`
)->add_space(
)->add_text( `sit`
)->add_space(
)->add_text( `amet`
)->display_text( out ).
ENDMETHOD.
METHOD add_text.
text &&= str.
ref = me.
ENDMETHOD.
METHOD add_space.
text &&= ` `.
ref = me.
ENDMETHOD.
METHOD display_text.
cl_run_ref->write( text ).
ENDMETHOD.
METHOD add_period.
text &&= `.`.
ref = me.
ENDMETHOD.
METHOD return_text.
str = me->text.
ENDMETHOD.
ENDCLASS.Expand the following collapsible section for an example class. The commented example class explores various aspects covered in the previous sections. You can create a demo class called zcl_demo_abap and copy and paste the following code. Once activated, you can choose F9 in ADT to run the class. The example is designed to display output in the console that shows the result of calling different methods.
🟢 Click to expand for example code
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
*&---------------------------------------------------------------------*
*& Attributes
*&---------------------------------------------------------------------*
"Instance attributes
DATA: inst_attr TYPE utclong,
inst_string TYPE string.
"Static attribute
CLASS-DATA stat_attr TYPE utclong.
"Attribute with the READ-ONLY addition. It is also possible for instance
"attributes. Such an attribute can only be read from outside the class,
"not changed. Inside the class, it can be changed. This also applies to
"subclasses (note that the example class does not allow inheritance).
CLASS-DATA read_only_attr TYPE string VALUE `read only` READ-ONLY.
*&---------------------------------------------------------------------*
*& Methods
*&---------------------------------------------------------------------*
"The parameter interfaces (signatures) of the methods are intended to
"demonstrate various syntax options described in the cheat sheet.
"Instance methods
METHODS:
"No parameter specified
inst_meth1,
"Single importing parameter
inst_meth2 IMPORTING ip TYPE string,
"Importing and exporting parameters
inst_meth3 IMPORTING ip1 TYPE i
ip2 TYPE i
EXPORTING ep TYPE i,
"Returning parameters
inst_meth4 RETURNING VALUE(ret) TYPE string,
inst_meth5 IMPORTING ip1 TYPE string
ip2 TYPE string
EXPORTING ep TYPE string
RETURNING VALUE(ret) TYPE string,
"Changing parameter
inst_meth6 CHANGING chg TYPE string,
"Raising exceptions
inst_meth7 IMPORTING ip1 TYPE i
ip2 TYPE i
RETURNING VALUE(ret) TYPE i
RAISING cx_sy_arithmetic_overflow,
inst_meth8 IMPORTING ip1 TYPE i
RETURNING VALUE(ret) TYPE string
RAISING cx_uuid_error,
"Instance constructor
"Instance constructors can optionally have importing parameters
"and raise exceptions.
constructor.
"Static methods
CLASS-METHODS:
"Options of formal parameter definitions
stat_meth1 IMPORTING REFERENCE(ip1) TYPE string "pass by reference (specifying REFERENCE(...) is optional)
ip2 TYPE string "pass by reference
VALUE(ip3) TYPE string "pass by value
RETURNING VALUE(ret) TYPE string, "pass by value (mandatory for returning parameters)
"OPTIONAL/DEFAULT additions
"Both additions denote that passing values is optional. DEFAULT: If not supplied,
"the default value specified is used.
stat_meth2 IMPORTING ip1 TYPE string DEFAULT `ABAP`
ip2 TYPE string OPTIONAL
RETURNING VALUE(ret) TYPE string_table,
"Generic types are possible for field symbols and method parameters
"All of the previous formal parameters are typed with complete types (e.g. type i).
"The following method includes several formal parameters typed with generic
"types. Find more information in the 'Data Types and Objects' cheat sheet.
"Note: Returning parameters must be completely typed.
stat_meth3 IMPORTING ip_data TYPE data "Any data type
ip_clike TYPE clike "Character-like data type (such as c, n, string, etc.)
ip_numeric TYPE numeric "Numeric type (such as i, p, decfloat34 etc.)
ip_any_table TYPE ANY TABLE "Any table type (standard, sorted, hashed)
RETURNING VALUE(ret) TYPE string, "No generic type possible for returning parameters
"Static constructor
"No parameters possible
class_constructor.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Note:
"This is a self-contained example. Usually, you must create an instance
"of a class first before using instance methods - when calling methods
"from outside, e.g. from another class. Within the class itself, you can
"indeed call the instance methods without a prior instance creation.
"To demonstrate 'calls from external', an instance of the class is
"nevertheless created in the example.
*&---------------------------------------------------------------------*
*& Constructors
*&---------------------------------------------------------------------*
"Instance constructor: Automatically called when a class is instantiated
"and an instance is created.
"Creating an instance of a class and accessing an instance attribute
"using the object component selector ->.
DATA(oref) = NEW zcl_demo_abap( ).
out->write( data = oref->inst_attr name = `oref->inst_attr` ).
"Creating more instances
"The example is implemented in a way that an instance attribute
"is assigned a time stamp when the instance constructor is called.
"As instance constructors are called once for each instance, the
"inst_attr values differ.
DATA(oref2) = NEW zcl_demo_abap( ).
out->write( data = oref2->inst_attr name = `oref2->inst_attr` ).
DATA(oref3) = NEW zcl_demo_abap( ).
out->write( data = oref3->inst_attr name = `oref3->inst_attr` ).
"Static constructor: Automatically and immediately called once for each class
"when calling a class for the first time in an internal session (e.g. an instance
"is created or a component is used).
"The example is implemented in a way that a static attribute is assigned a time
"stamp when the static constructor is called. The class was called with creating
"an instance above, and so the static constructor was called once. There is no new
"time stamp assigment, no new calls of the static constructor in this internal session.
"Therefore, the value of stat_attr is the same.
"The access is done using the class name, the class component selector =>, and
"the attribute name.
out->write( data = zcl_demo_abap=>stat_attr name = `zcl_demo_abap=>stat_attr` ).
"Static attributes are also accessible via the object reference variable
out->write( data = oref->stat_attr name = `oref->stat_attr` ).
"Checking that the values of the instance attribute that is modified when calling
"the instance constructor differ from instance to instance.
IF ( oref3->inst_attr > oref2->inst_attr )
AND ( oref2->inst_attr > oref->inst_attr ).
out->write( `Instance attribute check: All values differ.` ).
ELSE.
out->write( `Instance attribute check: At least one check is not successful.` ).
ENDIF.
"Checking that the value of the static attribute that is modified when calling
"the static constructor is identical from instance to instance (it is only changed
"when the class is called for the first time).
IF ( oref3->stat_attr = oref2->stat_attr )
AND ( oref2->stat_attr = oref->stat_attr )
AND ( oref->stat_attr = zcl_demo_abap=>stat_attr ).
out->write( `Static attribute check: All values are identical.` ).
ELSE.
out->write( `Static attribute check: At least one check is not successful.` ).
ENDIF.
"Excursion: See the note above. In the self-contained example, in this class itself, the
"components can be called without reference variable or providing the class name. The
"assumption in the following snippets of the example is that the class is called
"from outside and instances are created outside of the class, so the variable/class
"name are provided.
"The following access is possible in the same class (not outside of this class):
DATA(a) = inst_attr.
DATA(b) = stat_attr.
"The following is also possible inside the class (it is the only option outside of
"this class):
DATA(c) = oref->inst_attr.
DATA(d) = zcl_demo_abap=>stat_attr.
DATA(e) = oref->stat_attr.
*&---------------------------------------------------------------------*
*& Method calls
*&---------------------------------------------------------------------*
"Calling instance methods
"Instance methods are called using the object component selector ->
"via reference variables.
"--- Method without parameters ---
oref->inst_meth1( ).
"To show an effect of the method call in the example, the method implementation
"simply includes the change of an instance attribute value.
out->write( data = oref->inst_string name = `oref->inst_string` ).
"Notes:
"- See the method implementation of inst_meth1. It shows that
" instance methods can access both static and instance attributes.
"- As mentioned above regarding the attributes, in the same class and
" in this example, you can call the methods directly (without using
" a reference variable).
inst_meth1( ).
"--- Methods that specify importing parameters ---
"Similar to the inst_meth1 method, the implementation includes the
"change of an instance attribute.
"Notes:
"- In the method call, the caller exports values to the
" method having importing parameters defined. Therefore, the addition
" EXPORTING is relevant for the caller.
"- If a method only specifies importing parameters, specifying EXPORTING
" is optional.
"- If a method only specifies a single importing parameter, specifying
" EXPORTING and the formal parameter name is optional.
"Method with a single importing parameter (the following three method
"calls are basically the same)
"Method call that specifies EXPORTING and the formal parameter name
oref->inst_meth2( EXPORTING ip = `hello` ).
out->write( data = oref->inst_string name = `oref->inst_string` ).
"Method call that specifies the formal parameter, without EXPORTING
oref->inst_meth2( ip = `world` ).
out->write( data = oref->inst_string name = `oref->inst_string` ).
"Method call that only includes the actual parameter
oref->inst_meth2( `ABAP` ).
out->write( data = oref->inst_string name = `oref->inst_string` ).
"--- Methods that specify exporting parameters ---
"For the method call, specify EXPORTING for importing parameters,
"and IMPORTING for exporting parameters.
"The method implementation performs a calculation. The calculation
"result is assigned to the exporting parameter. You can assign the
"value to a suitable data object.
DATA calc_result1 TYPE i.
oref->inst_meth3( EXPORTING ip1 = 5
ip2 = 3
IMPORTING ep = calc_result1 ).
out->write( data = calc_result1 name = `calc_result1` ).
"Inline declaration is also possible.
oref->inst_meth3( EXPORTING ip1 = 2
ip2 = 4
IMPORTING ep = DATA(calc_result2) ).
out->write( data = calc_result2 name = `calc_result2` ).
"--- Methods that specify returning parameters ---
DATA(result1) = oref->inst_meth4( ).
out->write( data = result1 name = `result1` ).
"The RECEIVING addition is available in standalone method
"calls only if methods are defined with a returning parameter.
"Inline declaration is also possible here.
oref->inst_meth4( RECEIVING ret = DATA(result2) ).
out->write( data = result2 name = `result2` ).
"The following example method specifies multiple parameters,
"among them 2 output parameters (exporting and reporting).
"Functional method call
"In a functional method call, inline declaration is not possible
"for 'ep'.
DATA str1 TYPE string.
DATA(str2) = oref->inst_meth5( EXPORTING ip1 = `AB`
ip2 = `AP`
IMPORTING ep = str1 ).
out->write( data = str1 name = `str1` ).
out->write( data = str2 name = `str2` ).
"Standalone method call (including inline declarations)
oref->inst_meth5( EXPORTING ip1 = `AB`
ip2 = `AP`
IMPORTING ep = DATA(str3)
RECEIVING ret = DATA(str4) ).
out->write( data = str3 name = `str3` ).
out->write( data = str4 name = `str4` ).
"Returning parameters enable ...
"... the use of method calls in other statements, for example,
"in logical expressions, instead of storing the method call
"result in an extra variable.
IF oref->inst_meth4( ) IS INITIAL.
out->write( `Initial` ).
ELSE.
out->write( `Not initial` ).
ENDIF.
"... method chaining to write more concise code and avoid
"declaring helper variables.
"The following example uses a class that creates random integers.
"The 'create' method has a returning parameter. It returns an
"instance of the class (an object reference) based on which
"more methods can be called. Using method chaining, you can
"do the following in one go.
DATA(inst) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 10 ).
DATA(random_integer1) = inst->get_next( ).
DATA(random_integer2) = cl_abap_random_int=>create( seed = cl_abap_random=>seed( )
min = 1
max = 10 )->get_next( ).
out->write( data = random_integer1 name = `random_integer1` ).
out->write( data = random_integer2 name = `random_integer2` ).
"--- Method that specifies a changing parameter ---
"Changing parameters should be reserved for changing an existing
"local variable and value.
"The method implementation includes the demonstration of the
"self-reference 'me'. For this purpose, a data object is created
"in the method implementation that has the same name as a data
"object declared in the class's declaration part.
"Changing the value of the instance attribute with the same name
"as the local data object in the method implementation.
oref->inst_string = `TEST`.
DATA local_var TYPE string VALUE `hello`.
oref->inst_meth6( CHANGING chg = local_var ).
out->write( data = local_var name = `local_var` ).
"--- Methods that specify RAISING ---
"The following example method declares an exception of the category
"CX_DYNAMIC_CHECK. That is, the check is not performed until runtime.
"There is no syntax warning shown at compile time.
"The ipow function is included in the method implementation. The
"second example raises the exception.
"No TRY control structure, no syntax warning at compile time. However,
"the calculation works.
DATA(power_res1) = oref->inst_meth7( ip1 = 5 ip2 = 2 ).
out->write( data = power_res1 name = `power_res1` ).
"The example raises the exception because the resulting number is too high.
"Not catching the exception results in a runtime error.
TRY.
DATA(power_res2) = oref->inst_meth7( ip1 = 10 ip2 = 10 ).
out->write( data = power_res2 name = `power_res2` ).
CATCH cx_sy_arithmetic_overflow.
out->write( `cx_sy_arithmetic_overflow was raised` ).
ENDTRY.
"The following example method declares an exception of the category
"CX_STATIC_CHECK. That is, it is statically checked. Without the
"TRY control structure and catching the exception, a syntax warning
"is displayed. And in the case of the example implementation,
"the exception is indeed raised. Not catching the exception results
"in a runtime error.
TRY.
DATA(test) = oref->inst_meth8( ip1 = 1 ).
out->write( data = test name = `test` ).
CATCH cx_uuid_error.
out->write( `cx_uuid_error was raised` ).
ENDTRY.
"A syntax warning is displayed for the following method call.
"DATA(test2) = oref->inst_meth8( ip1 = 1 ).
"Calling static methods
"The method definitions/implementations cover further aspects.
"--- Pass by reference/value ---
"The following example method emphasizes pass by reference and
"by value.
"Notes:
"- Returning parameters can only be declared with VALUE(...)
"- When passing by reference, the content of the data objects
" cannot be changed in the method implementation.
"- The method implementation includes that ...
" - attributes declared with READ-ONLY can be changed within
" the class they are declared.
" - static methods can only access static attributes.
DATA(res) = zcl_demo_abap=>stat_meth1( ip1 = `a` "pass by reference (declaration with REFERENCE(...))
ip2 = `b` "pass by reference (without REFERENCE(...))
ip3 = `c` "pass by value (declaration with VALUE(...))
).
out->write( data = res name = `res` ).
"--- OPTIONAL/DEFAULT additions ---
"The method implementation includes the predicate expression IS SUPPLIED
"that checks whether a formal parameter is populated.
DATA(res_tab1) = zcl_demo_abap=>stat_meth2( ip1 = `aaa` ip2 = `bbb` ).
out->write( data = res_tab1 name = `res_tab1` ).
DATA(res_tab2) = zcl_demo_abap=>stat_meth2( ip1 = `ccc` ).
out->write( data = res_tab2 name = `res_tab2` ).
DATA(res_tab3) = zcl_demo_abap=>stat_meth2( ip2 = `ddd` ).
out->write( data = res_tab3 name = `res_tab3` ).
DATA(res_tab4) = zcl_demo_abap=>stat_meth2( ).
out->write( data = res_tab4 name = `res_tab4` ).
"--- Generically typed formal parameters ---
"In the following method calls, various data objects are
"assigned to formal parameters. Note that returning parameters
"must be completely typed.
"In the example, the value passed for parameter ip_clike (which is
"convertible to type string) is returned.
DATA(res_gen1) = zcl_demo_abap=>stat_meth3( ip_data = VALUE string_table( ( `hi` ) ) "any data type
ip_clike = abap_true "Character-like data type (such as c, n, string, etc.)
ip_numeric = 1 "Numeric type (such as i, p, decfloat34 etc.)
ip_any_table = VALUE string_table( ( `ABAP` ) ) "Any table type (standard, sorted, hashed)
).
out->write( data = res_gen1 name = `res_gen1` ).
DATA(res_gen2) = zcl_demo_abap=>stat_meth3( ip_data = 123
ip_clike = 'ABAP'
ip_numeric = CONV decfloat34( '1.23' )
ip_any_table = VALUE string_hashed_table( ( `hello` ) ( `world` ) )
).
out->write( data = res_gen2 name = `res_gen2` ).
ENDMETHOD.
METHOD class_constructor.
"Assigning the current UTC timestamp to a static attribute
stat_attr = utclong_current( ).
ENDMETHOD.
METHOD constructor.
"Assigning the current UTC timestamp to an instance attribute
inst_attr = utclong_current( ).
ENDMETHOD.
METHOD inst_meth1.
inst_string = `Changed in inst_meth1`.
"Instance methods can access both static and instance attributes.
DATA(a) = inst_attr.
DATA(b) = stat_attr.
ENDMETHOD.
METHOD inst_meth2.
inst_string = |Changed in inst_meth2. Content of passed string: { ip }|.
ENDMETHOD.
METHOD inst_meth3.
ep = ip1 + ip2.
ENDMETHOD.
METHOD inst_meth4.
ret = |This string was assigned to the returning parameter at { utclong_current( ) }|.
ENDMETHOD.
METHOD inst_meth5.
ep = |Strings '{ ip1 }' and '{ ip2 }' were assigned to the exporting parameter at { utclong_current( ) }|.
ret = |Strings '{ ip1 }' and '{ ip2 }' were assigned to the returning parameter at { utclong_current( ) }|.
ENDMETHOD.
METHOD inst_meth6.
"Demonstrating the self-reference 'me'
"Its use is optional. The following data object intentionally
"has the same name as an instance attribute specified in the
"class's declaration part.
DATA inst_string TYPE string.
inst_string = `Local string`.
chg = |The local data object was changed: '{ to_upper( chg ) }'\nChecking the self-reference me:\ninst_string: '{ inst_string }'\nme->inst_string: '{ me->inst_string }'|.
ENDMETHOD.
METHOD inst_meth7.
ret = ipow( base = ip1 exp = ip2 ).
ENDMETHOD.
METHOD inst_meth8.
IF ip1 = 1.
RAISE EXCEPTION TYPE cx_uuid_error.
ELSE.
ret = `No exception was raised.`.
ENDIF.
ENDMETHOD.
METHOD stat_meth1.
"Static methods can only access static attributes.
"DATA(test1) = inst_attr.
DATA(test2) = stat_attr.
"Only read access possible when parameters are passed by value
DATA(a) = ip1.
DATA(b) = ip2.
"Write access is not possible (however, if you need to work with them
"and change the content, you can create copies as above)
"ip1 = `y`.
"ip2 = `z`.
"Pass by value, modification is possible
ip3 = to_upper( ip3 ) && `##`.
"Modifying a read only attribute is possible in the class
"in which it is declared.
read_only_attr = `Read-only attribute was modified`.
ret = |ip1 = '{ ip1 }', ip2 = '{ ip2 }', ip3 (modified) = '{ ip3 }' / read_only_attr = '{ read_only_attr }'|.
ENDMETHOD.
METHOD stat_meth2.
"Using IS SUPPLIED in an IF control structure
IF ip1 IS SUPPLIED.
APPEND |ip1 is supplied, value: '{ ip1 }'| TO ret.
ELSE.
APPEND |ip1 is not supplied, value: '{ ip1 }'| TO ret.
ENDIF.
"Using IS SUPPLIED with the COND operator
APPEND COND #( WHEN ip2 IS SUPPLIED
THEN |ip2 is supplied, value: '{ ip2 }'|
ELSE |ip2 is not supplied, value: '{ ip2 }'| ) TO ret.
ENDMETHOD.
METHOD stat_meth3.
"You may check the content in the debugger.
DATA(a) = REF #( ip_data ).
DATA(b) = REF #( ip_clike ).
DATA(c) = REF #( ip_numeric ).
DATA(d) = REF #( ip_any_table ).
ret = ip_clike.
ENDMETHOD.
ENDCLASS.The following table covers a selection of aspects about inheritance. The code snippets demonstrate local classes.
| Aspect | Notes/Code examples |
|
Superclasses and subclasses |
The inheritance tree of the example classes is as follows: The classes are without any component specifications for demonstration purposes. |
|
Components specified in superclasses |
The inheritance tree of the following example classes is as follows: The code snippet includes various data object declarations and value assignments by exploring:
|
|
Redefinition of superclass methods |
The inheritance tree of the following example classes looks as follows: The example explores the redefinition of methods. Global class to run the example and visualize the implementations of the local classes in the CCIMP include. The output should be as follows: Local classes in the CCIMP include: |
|
Visibility of components |
|
|
Additions impacting inheritance |
|
|
Constructors |
The inheritance tree of the following example classes is as follows: This example explores how instance and static constructors can be specified. It shows that subclasses can determine their own instantiation independently of the superclass. The visibility of the constructor cannot be more specific than that of the
The inheritance tree of the following example classes is as follows: This example explores the order of instance and static constructor calls during object creation. The constructors add strings to a string table. To visualize the output, run the global class, which includes object creations. Refer to the notes on the example output below. Global class: Local classes in the CCIMP include: Notes on the output:
If you comment out |
|
|
|
The table below includes selected syntax related to inheritance in class and method declarations. It also includes additions related to instantiation.
[!NOTE] - Some of the syntax options have already been mentioned previously. This is to summarize. - The code examples show local classes and interfaces declared, for example, in the CCIMP include of a class pool. - The snippets provided do not represent all possible syntax combinations. For the complete picture, refer to the ABAP Keyword Documentation. Additional syntax options are available in the context of friendship (GLOBAL FRIENDS/FRIENDS), testing (FOR TESTING), RAP (FOR BEHAVIOR OF; to declare ABAP behavior pools), and more. - The order of the additions can vary.
Declarations in Classes
| Syntax Example | Details |
|
The following code example demonstrates local classes (no |
|
This class permits inheritance because it does not include the The following code example demonstrates local classes: |
|
The following code example demonstrates local classes: |
|
The following code example demonstrates local classes: |
|
The following code example demonstrates local classes: |
|
The following code example demonstrates local classes: |
Declarations in Instance Methods
| Syntax Example | Details |
|
The following code example demonstrates local classes: |
|
The following code example demonstrates local classes: |
|
Find information on constructors in the previous section. The following code example demonstrates constructors. When the constructors are called, a string is added to an internal table (a static attribute). You can try out the example and explore the calling of constructors as follows:
|
|
The following code example demonstrates local classes: |
[!NOTE] This example is also included in the ABAP cheat sheet repository: zcl_demo_abap_oo_inheritance_1
Expand the following collapsible section for example classes. The example classes explore inheritance and demonstrate a selection of the inheritance-related syntax described above. The inheritance tree consists of four example classes. The base class includes the implementation of the classrun interface. The example is designed to output information to the console. So, you can execute this class using F9 in ADT. The purpose of the example and information output is to visualize and explore concepts and syntax related to inheritance, checking out when and how methods are called, redefining methods, abstract and final classes and methods.
🟢 Click to expand for more information and example code
The inheritance tree of the example classes is as follows:
ZCL_DEMO_ABAP_OO_INHERITANCE_1
|
|--ZCL_DEMO_ABAP_OO_INHERITANCE_2
| |
| |--ZCL_DEMO_ABAP_OO_INHERITANCE_3
| | |
| | |--ZCL_DEMO_ABAP_OO_INHERITANCE_4Notes on the example:
ZCL_DEMO_ABAP_OO_INHERITANCE_1 class by getting callstack information to determine which method in which class was called by whom. Based on the retrieved class and method names, RTTI is used to get detailed information about the methods.ZCL_DEMO_ABAP_OO_INHERITANCE_1FINAL, so no redefinition is possible in subclasses.ZCL_DEMO_ABAP_OO_INHERITANCE_2ZCL_DEMO_ABAP_OO_INHERITANCE_1 and allows inheritance itself CREATE PROTECTED, so the class can only be instantiated in methods of its subclasses, of the class itself, and of its friends ZCL_DEMO_ABAP_OO_INHERITANCE_1 like this DATA(oref) = NEW zcl_demo_abap_oo_inheritance_2( ). It is not possible. In ZCL_DEMO_ABAP_OO_INHERITANCE_3 and ZCL_DEMO_ABAP_OO_INHERITANCE_4, for example, it is possible.FINAL, so no redefinition is possible in subclassesZCL_DEMO_ABAP_OO_INHERITANCE_1.ZCL_DEMO_ABAP_OO_INHERITANCE_3ZCL_DEMO_ABAP_OO_INHERITANCE_2 and thus from ZCL_DEMO_ABAP_OO_INHERITANCE_1 ABSTRACT addition, so no instances can be created from the classABSTRACT addition, so they can only be implemented in subclasses (there is no implementation of these methods in the class) FINAL REDEFINITION, so a further redefinition in subclasses is not possible.ZCL_DEMO_ABAP_OO_INHERITANCE_4ZCL_DEMO_ABAP_OO_INHERITANCE_3 and thus from ZCL_DEMO_ABAP_OO_INHERITANCE_2 and ZCL_DEMO_ABAP_OO_INHERITANCE_1FINAL and so does not allow inheritance FINAL REDEFINITION in ZCL_DEMO_ABAP_OO_INHERITANCE_3)super->....To try the example classes out, create four demo classes named
ZCL_DEMO_ABAP_OO_INHERITANCE_1 ZCL_DEMO_ABAP_OO_INHERITANCE_2ZCL_DEMO_ABAP_OO_INHERITANCE_3ZCL_DEMO_ABAP_OO_INHERITANCE_4and paste the code into it. After activation, choose F9 in ADT to execute the class ZCL_DEMO_ABAP_OO_INHERITANCE_1. The example is set up to display output in the console.
Class ZCL_DEMO_ABAP_OO_INHERITANCE_1
CLASS zcl_demo_abap_oo_inheritance_1 DEFINITION
PUBLIC
CREATE PUBLIC .
PUBLIC SECTION.
"Classrun interface
INTERFACES if_oo_adt_classrun.
"Instance/static constructor declarations
METHODS constructor.
CLASS-METHODS class_constructor.
"Instance method declarations
METHODS meth_public_1.
"Final method
METHODS meth_public_1_final FINAL.
"Components used for logging information about method calls
TYPES: BEGIN OF s_log,
method TYPE string,
implemented_where TYPE string,
called_from TYPE syrepid,
is_inherited TYPE abap_boolean,
is_redefined TYPE abap_boolean,
is_final TYPE abap_boolean,
visibility TYPE abap_visibility,
is_static_method TYPE abap_boolean,
called_at TYPE utclong,
END OF s_log,
t_log TYPE TABLE OF s_log WITH EMPTY KEY.
CLASS-DATA log_tab TYPE t_log.
CLASS-METHODS get_method_info RETURNING VALUE(info) TYPE s_log.
PROTECTED SECTION.
METHODS meth_protected_1.
PRIVATE SECTION.
METHODS meth_private_1.
ENDCLASS.
CLASS zcl_demo_abap_oo_inheritance_1 IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"----- First level in the inheritance hierarchy ----
"Creating an instance of the class
DATA(oref_super) = NEW zcl_demo_abap_oo_inheritance_1( ).
"Calling methods of the class
oref_super->meth_public_1( ).
oref_super->meth_public_1_final( ).
oref_super->meth_protected_1( ).
oref_super->meth_private_1( ).
"----- Second level in the inheritance hierarchy ----
"The instance creation and method calling is delegated to
"a static method in the class
zcl_demo_abap_oo_inheritance_2=>perform_meth_calls_2( ).
"----- Third level in the inheritance hierarchy ----
"Note: The class zcl_demo_abap_oo_inheritance_3 is abstract and contains
"both non-abstract and abstract instance methods. Instances of abstract
"classes cannot be created. So, the following statement is not possible.
"DATA(oref_3) = NEW zcl_demo_abap_oo_inheritance_3( ).
"Instance components of an abstract class can be accessed via its subclasses.
"zcl_demo_abap_oo_inheritance_4 inherits from zcl_demo_abap_oo_inheritance_3 and
"redefines methods of zcl_demo_abap_oo_inheritance_3. Both abstract methods (which
"are mandatory to implement) and non-abstract methods are redefined. To also access
"the method implementations of the non-abstract instance methods of
"zcl_demo_abap_oo_inheritance_3, the respective implementations of the redefined
"methods in zcl_demo_abap_oo_inheritance_4 include method calls to the direct
"superclass using the syntax super->meth( ).. The instance methods of
"zcl_demo_abap_oo_inheritance_3 are called in the context of the static method call
"via zcl_demo_abap_oo_inheritance_4 below.
"----- Fourth level in the inheritance hierarchy ----
"As above, the instance creation and method calling is delegated to
"a static method in the class. This method call includes method calls to
"non-abstract instance methods implemented in zcl_demo_abap_oo_inheritance_3.
zcl_demo_abap_oo_inheritance_4=>perform_meth_calls_4( ).
"Writing the log table to the console
out->write( data = log_tab name = `log_tab` ).
"Excursion: Using RTTI to retrieve the name of the superclass
"As this class starts an inheritance hierarchy, the superclass of this class
"is the root class OBJECT.
DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( 'ZCL_DEMO_ABAP_OO_INHERITANCE_1' ) ).
DATA(superclass) = tdo_cl->get_super_class_type( )->get_relative_name( ).
out->write( |\n\n| ).
out->write( data = superclass name = `superclass` ).
ENDMETHOD.
METHOD class_constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_private_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1_final.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD get_method_info.
"This method retrieves callstack information to determine which method in which
"class was called by whom.
"Based on the retrieved class and method names, RTTI is used to get detailed
"information about methods (such as the visibility or whether the method is
"inherited, redefined, final, and a static method).
"Getting callstack information
DATA(call_stack_tab) = xco_cp=>current->call_stack->full( )->from->position( 2
)->to->position( 2 )->as_text( xco_cp_call_stack=>format->adt( )
)->get_lines( )->value.
IF lines( call_stack_tab ) < 2.
RETURN.
ENDIF.
LOOP AT call_stack_tab INTO DATA(wa) TO 2.
DATA(tabix) = sy-tabix.
SPLIT wa AT ` ` INTO TABLE DATA(entry).
DELETE entry WHERE table_line IS INITIAL.
DATA(class_name) = condense( val = entry[ 1 ] to = `` ).
IF tabix = 1.
info-implemented_where = class_name.
DATA(meth_name) = condense( val = to_upper( entry[ 2 ] ) to = `` ).
info-method = meth_name.
IF class_name IS NOT INITIAL AND meth_name IS NOT INITIAL.
DATA(tdo_cl) = CAST cl_abap_classdescr( cl_abap_typedescr=>describe_by_name( class_name ) ).
DATA(methods_cl) = tdo_cl->methods.
DATA(meth_info) = VALUE #( methods_cl[ name = meth_name ] OPTIONAL ).
IF meth_info IS NOT INITIAL.
info-is_inherited = meth_info-is_inherited.
info-is_redefined = meth_info-is_redefined.
info-is_final = meth_info-is_final.
info-visibility = meth_info-visibility.
info-is_static_method = meth_info-is_class.
ENDIF.
ENDIF.
ELSE.
info-called_from = class_name.
ENDIF.
ENDLOOP.
ENDMETHOD.
ENDCLASS.Class ZCL_DEMO_ABAP_OO_INHERITANCE_2
CLASS zcl_demo_abap_oo_inheritance_2 DEFINITION
INHERITING FROM zcl_demo_abap_oo_inheritance_1
PUBLIC
CREATE PROTECTED .
PUBLIC SECTION.
"Instance/static constructor declarations
METHODS constructor.
CLASS-METHODS class_constructor.
"Instance method declarations
METHODS meth_public_2.
METHODS meth_public_2_final FINAL.
"Static method declaration for display purposes
CLASS-METHODS perform_meth_calls_2.
"Redefining method from the class one level up in the inheritance hierarchy
"(i.e. the direct superclass)
METHODS meth_public_1 REDEFINITION.
"Excursions:
"- Redefining the final public method of the superclass is not possible.
"- The same applies to constructors.
"- The following type has the same name as a type in the superclass. Since components
" are inherited, the following declaration is not possible.
"TYPES t_log TYPE string_table.
"- Similary, the log table, which is a static component in the superclass, can be
" referenced in the method implementations using 'log_table'. Using the class name
" and => is also possible, but not required.
"INSERT VALUE #( ) INTO TABLE zcl_demo_abap_oo_inheritance_1=>log_tab.
PROTECTED SECTION.
"Instance method declaration
METHODS meth_protected_2.
"Redefining method from the class one level up in the inheritance hierarchy
"(i.e. the direct superclass)
METHODS meth_protected_1 REDEFINITION.
PRIVATE SECTION.
"Ecursion:
"- The following declarations are not possible.
"- Private methods cannot be redefined.
"METHODS meth_private_1 REDEFINITION.
"- Abstract methods can only be declared in abstract classes. And, since
" private methods cannot be redefined, abstract private methods are not
" possible.
"METHODS meth_private_2_abstract ABSTRACT.
ENDCLASS.
CLASS zcl_demo_abap_oo_inheritance_2 IMPLEMENTATION.
METHOD class_constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD constructor.
super->constructor( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_2.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_2_final.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_2.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_1.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD perform_meth_calls_2.
"Method of this class
"Creating an instance of the class
DATA(oref_2) = NEW zcl_demo_abap_oo_inheritance_2( ).
"Calling methods of this class
oref_2->meth_public_2( ).
oref_2->meth_public_2_final( ).
oref_2->meth_protected_2( ).
"Calling redefined methods from the class one level up in the inheritance hierarchy (direct superclass)
oref_2->meth_protected_1( ).
oref_2->meth_public_1( ).
ENDMETHOD.
ENDCLASS.Class ZCL_DEMO_ABAP_OO_INHERITANCE_3
CLASS zcl_demo_abap_oo_inheritance_3 DEFINITION
INHERITING FROM zcl_demo_abap_oo_inheritance_2
PUBLIC
ABSTRACT
CREATE PUBLIC .
PUBLIC SECTION.
"Instance/static constructor declarations
METHODS constructor.
CLASS-METHODS class_constructor.
"Instance method declarations
METHODS meth_public_3.
"Abstract method
METHODS meth_public_3_abstract ABSTRACT.
"Redefining methods from the class ...
"... one level up in the inheritance hierarchy (i.e. the direct superclass)
METHODS meth_public_2 REDEFINITION.
"... two levels up in the inheritance hierarchy
METHODS meth_public_1 REDEFINITION.
PROTECTED SECTION.
"Instance method declarations
METHODS meth_protected_3.
"Abstract method
METHODS meth_protected_3_abstract ABSTRACT.
"Redefining methods from the class ...
"... one level up in the inheritance hierarchy (i.e. the direct superclass)
METHODS meth_protected_2 REDEFINITION.
"... two levels up in the inheritance hierarchy
"Specifying the FINAL addition
METHODS meth_protected_1 FINAL REDEFINITION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap_oo_inheritance_3 IMPLEMENTATION.
METHOD class_constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD constructor.
super->constructor( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_3.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_3.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_2.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_2.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_1.
"Reimplementing a method from the class two levels up in the inheritance hierarchy
"Note that the method is specified with FINAL REDEFINITION. So, a further redefinition in subclasses is not possible.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1.
"Reimplementing a method from the class two levels up in the inheritance hierarchy
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
ENDCLASS.Class ZCL_DEMO_ABAP_OO_INHERITANCE_4
CLASS zcl_demo_abap_oo_inheritance_4 DEFINITION
INHERITING FROM zcl_demo_abap_oo_inheritance_3
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
"Instance/static constructor declarations
METHODS constructor.
CLASS-METHODS class_constructor.
"Instance method declaration
METHODS meth_public_4.
"Static method declaration for display purposes
CLASS-METHODS perform_meth_calls_4.
"Redefining methods from the class ...
"... one level up in the inheritance hierarchy (i.e. the direct superclass)
METHODS meth_public_3 REDEFINITION.
"Note: Redefining the abstract method here is mandatory.
METHODS meth_public_3_abstract REDEFINITION.
"... two levels up in the inheritance hierarchy
METHODS meth_public_2 REDEFINITION.
"... three levels up in the inheritance hierarchy
METHODS meth_public_1 REDEFINITION.
PROTECTED SECTION.
"Instance method declaration
METHODS meth_protected_4.
"Redefining methods from the class ...
"... one level up in the inheritance hierarchy (i.e. the direct superclass)
METHODS meth_protected_3 REDEFINITION.
"Note: Redefining the abstract method here is mandatory.
METHODS meth_protected_3_abstract REDEFINITION.
"... two levels up in the inheritance hierarchy
METHODS meth_protected_2 REDEFINITION.
"... three levels up in the inheritance hierarchy
"The meth_protected_1 method is specified with FINAL REDEFINITION in the
"direct superclass. Therefore, a further redefinition is not possible.
"The following statement is not possible.
"METHODS meth_protected_1 REDEFINITION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap_oo_inheritance_4 IMPLEMENTATION.
METHOD class_constructor.
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD constructor.
super->constructor( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_4.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_4.
"Method of this class
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_3.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
"Calling this instance method that is redefined in the abstract direct superclass (instances of abstract classes cannot be created)
"by referring to the direct superclass using the syntax super->...
super->meth_public_3( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_3.
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
"This method is a non-abstract instance method of the abstract direct superclass. Instances of abstract classes
"cannot be created. The syntax super->meth is used to also call instance methods of the abstract direct superclass
"for output purposes.
super->meth_protected_3( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_3_abstract.
"Implementating abstract methods are only possible in subclasses of abstract classes
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_3_abstract.
"Implementating abstract methods are only possible in subclasses of abstract classes
"Reimplementing a method from the class one level up in the inheritance hierarchy (direct superclass)
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_2.
"Reimplementing a method from the class two levels up in the inheritance hierarchy
"Calling this instance method that is redefined in the abstract direct superclass (instances of abstract
"classes cannot be created) by referring to the direct superclass using the syntax super->....
super->meth_public_2( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_protected_2.
"Reimplementing a method from the class two levels up in the inheritance hierarchy
"Calling this instance method that is redefined in the abstract direct superclass (instances of abstract
"classes cannot be created) by referring to the direct superclass using the syntax super->....
super->meth_protected_2( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD meth_public_1.
"Reimplementing a method from the class three levels up in the inheritance hierarchy
"Calling this instance method that is redefined in the abstract direct superclass (instances of abstract
"classes cannot be created) by referring to the direct superclass using the syntax super->....
super->meth_public_1( ).
INSERT VALUE #( called_at = utclong_current( ) ) INTO TABLE log_tab ASSIGNING FIELD-SYMBOL(<fs>).
<fs> = CORRESPONDING #( BASE ( <fs> ) get_method_info( ) EXCEPT called_at ).
ENDMETHOD.
METHOD perform_meth_calls_4.
"Method of this class
"Creating an instance of the class
DATA(oref_4) = NEW zcl_demo_abap_oo_inheritance_4( ).
"Calling methods of this class
oref_4->meth_public_4( ).
oref_4->meth_protected_4( ).
"Calling redefined methods from the class ...
"... one level up in the inheritance hierarchy (direct superclass)
"Among them are abstract methods that can only be implemented in subclasses.
"Note that the implementations of the non-abstract, redefined methods in this
"class includes method calls of the abstract direct superclass so that
"also these implementations are called for output purposes.
oref_4->meth_public_3( ).
oref_4->meth_public_3_abstract( ).
oref_4->meth_protected_3( ).
oref_4->meth_protected_3_abstract( ).
"... two levels up in the inheritance hierarchy
oref_4->meth_public_2( ).
oref_4->meth_protected_2( ).
"... three levels up in the inheritance hierarchy
oref_4->meth_public_1( ).
"Note: The following method call calls the method implementation in
"class zcl_demo_abap_oo_inheritance_3. The method is specified with FINAL
"REDEFINITION. So, it cannot be redefined in this class inheriting from
"zcl_demo_abap_oo_inheritance_3.
oref_4->meth_protected_1( ).
ENDMETHOD.
ENDCLASS.The object orientation concept polymorphism means you can address differently implemented methods belonging to different objects of different classes using one and the same reference variable, for example, object reference variables pointing to a superclass can point to objects of a subclass.
Note the concept of static and dynamic type in this context:
static and a dynamic type.
DATA oref TYPE REF TO cl, you determine the static type, i. e.cl - a class - is used to declare the reference variable that is statically defined in the code. This is the class of an object to which the reference variable points to.
[!TIP] - The following basic rule applies: The static type is always more general than or the same as the dynamic type. The other way round: The dynamic type is always more special than or equal to the static type. - That means: - If the static type is a class, the dynamic type must be the same class or one of its subclasses. - If the static type is an interface, the dynamic type must implement the interface.
although the types are different, the assignment is done using the assignment operator = that triggers an upcast automatically.
downcast. Here, the assignability is not checked until runtime. The downcast - in contrast to upcasts - must be triggered explicitly using the casting operator CAST. You might see code using the older operator ?=.
Variables](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenconversion_references.htm).
As an example, assume there is an inheritance tree with lcl_super as the superclass and lcl_sub as a direct subclass. lcl_sub2 is a direct subclass of lcl_sub.
In the following code snippet, the rule is met since the superclass is either the same as or more generic than the subclass (the subclass has, for example, redefined methods and is, thus, more specific). Hence, the assignment of an object reference variable pointing to the subclass to a variable pointing to a superclass works. An upcast is triggered. After this casting, the type of oref_super has changed and the methods of lcl_sub can be accessed via oref_super.
"Creating object references
DATA(oref_super) = NEW lcl_super( ).
DATA(oref_sub) = NEW lcl_sub( ).
"Upcast
oref_super = oref_sub.
"The casting might be done when creating the object.
DATA super_ref TYPE REF TO lcl_super.
super_ref = NEW lcl_sub( ).manually. Just an assignment like oref_sub = oref_super. does not work. A syntax error occurs saying the right-hand variable's type cannot be converted to the left-hand variable's type.
CAST (or you might see code using the older operator ?=) to overcome this syntax error (but just the syntax error!). Note: You might also use these casting operators for the upcasts. That means oref_super = oref_sub. has the same effect as oref_super = CAST #( oref_sub ).. Using the casting operator for upcasts is usually not necessary.
oref_sub = CAST #( oref_super ). does not throw a syntax error but it does not work in this example either because it violates the rule mentioned above (oref_sub is more specific than oref_super).on specific classes, you can use the predicate expression [IS [NOT] INSTANCE OF](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenlogexp_instance_of.htm) or the case distinction CASE TYPE OF. Carrying out an upcast before the downcast ensures that the left-hand variable's type is compatible to the right-hand variable's type.
DATA(oref_super) = NEW lcl_super( ).
DATA(oref_sub) = NEW lcl_sub( ).
DATA(oref_sub2) = NEW lcl_sub2( ).
"Downcast impossible (oref_sub is more specific than oref_super);
"the exception is caught here
TRY.
oref_sub = CAST #( oref_super ).
CATCH cx_sy_move_cast_error INTO DATA(e).
...
ENDTRY.
"Working downcast with a prior upcast
oref_super = oref_sub2.
"Due to the prior upcast, the following check is actually not necessary.
IF oref_super IS INSTANCE OF lcl_sub.
oref_sub = CAST #( oref_super ).
...
ENDIF.
"Excursion RTTI: Downcasts, CAST and method chaining
"Downcasts particularly play, for example, a role in the context of
"retrieving type information using RTTI. Method chaining is handy
"because it reduces the lines of code in this case.
"The example below shows the retrieval of type information
"regarding the components of a structure.
"Due to the method chaining in the second example, the three
"statements in the first example are reduced to one statement.
DATA struct4cast TYPE zdemo_abap_carr.
DATA(rtti_a) = cl_abap_typedescr=>describe_by_data( struct4cast ).
DATA(rtti_b) = CAST cl_abap_structdescr( rtti_a ).
DATA(rtti_c) = rtti_b->components.
DATA(rtti_d) = CAST cl_abap_structdescr(
cl_abap_typedescr=>describe_by_data( struct4cast )
)->components.The following example class demonstrates upcasts and downcasts using multiple local classes to avoid the extra creation of multiple global classes and to have a self-contained example. To try the example out, create a demo class named zcl_demo_abap. If it already exists, reuse it. Otherwise, create a new class with a different name. Paste the code into it. If you choose a different class name, update the class name in the code snippet accordingly. Note to copy the code in the Global Class and Local Types tabs in ADT. After activation, choose F9 in ADT to execute the class. The example is not set up to display output in the console, but it contains comments. You may want to set break points and walk through the demo assignments.
The inheritance tree of the local example classes is as follows:
LCL1
|
|--LCL2
|
|--LCL3
| |
| |--LCL4| Class include | Code |
|
Global class |
|
|
CCIMP include (Local Types tab in ADT) |
|
🟢 Example with local classes implementing a local interface
| Class include | Code |
|
Global class |
|
|
CCIMP include (Local Types tab in ADT) |
|
The examples in the following code snippet use object reference variables to illustrate the class hierarchy of the Runtime Type Services (RTTS), which is covered in more detail in the Dynamic Programming cheat sheet.
Hierarchy tree of the classes:
CL_ABAP_TYPEDESCR
|
|--CL_ABAP_DATADESCR
| |
| |--CL_ABAP_ELEMDESCR
| | |
| | |--CL_ABAP_ENUMDESCR
| |
| |--CL_ABAP_REFDESCR
| |--CL_ABAP_COMPLEXDESCR
| |
| |--CL_ABAP_STRUCTDESCR
| |--CL_ABAP_TABLEDESCR
|
|--CL_ABAP_OBJECTDESCR
|
|--CL_ABAP_CLASSDESCR
|--CL_ABAP_INTFDESCRExamples:
*&---------------------------------------------------------------------*
*& Object reference variables
*&---------------------------------------------------------------------*
"Static and dynamic types
"Defining an object reference variable with a static type
DATA tdo TYPE REF TO cl_abap_typedescr.
"Retrieving type information
"The reference the reference variable points to is either cl_abap_elemdescr,
"cl_abap_enumdescr, cl_abap_refdescr, cl_abap_structdescr, or cl_abap_tabledescr.
"So, it points to one of the subclasses. The static type of tdo refers to
"cl_abap_typedescr, however, the dynamic type is one of the subclasses mentioned.
"in the case of the example, it is cl_abap_elemdescr. Check in the debugger.
DATA some_string TYPE string.
tdo = cl_abap_typedescr=>describe_by_data( some_string ).
"Some more object reference variables
DATA tdo_super TYPE REF TO cl_abap_typedescr.
DATA tdo_elem TYPE REF TO cl_abap_elemdescr.
DATA tdo_data TYPE REF TO cl_abap_datadescr.
DATA tdo_gen_obj TYPE REF TO object.
*&---------------------------------------------------------------------*
*& Upcasts
*&---------------------------------------------------------------------*
"Moving up the inheritance tree
"Assignments:
"- If the static type of target variable is less specific or the same, an assignment works.
"- The target variable inherits the dynamic type of the source variable.
"Static type of target variable is the same
tdo_super = tdo.
"Examples for static types of target variables that are less specific
"Target variable has the generic type object
tdo_gen_obj = tdo.
"Target variable is less specific because the direct superclass of cl_abap_elemdescr
"is cl_abap_datadescr
"Note: In the following three assignments, the target variable remains initial
"since the source variables do not (yet) point to any object.
tdo_data = tdo_elem.
"Target variable is less specific because the direct superclass of cl_abap_datadescr
"is cl_abap_typedescr
tdo_super = tdo_data.
"Target variable is less specific because the class cl_abap_typedescr is higher up in
"the inheritance tree than cl_abap_elemdescr
tdo_super = tdo_elem.
"The casting happens implicitly. You can also excplicitly cast and use
"casting operators, but it is usually not required.
tdo_super = CAST #( tdo ).
tdo_super ?= tdo.
"In combination with inline declarations, the CAST operator can be used to provide a
"reference variable with a more general type.
DATA(tdo_inl_cast) = CAST cl_abap_typedescr( tdo_elem ).
CLEAR: tdo_super, tdo_elem, tdo_data, tdo_gen_obj.
*&---------------------------------------------------------------------*
*& Downcasts
*&---------------------------------------------------------------------*
"Moving down the inheritance tree
"Assignments:
"- If the static type of the target variable is more specific than the static type
" of the source variable, performing a check whether it is less specific or the same
" as the dynamic type of the source variable is required at runtime before the assignment
"- The target variable inherits the dynamic type of the source variable, however, the target
" variable can accept fewer dynamic types than the source variable
"- Downcasts are always performed explicitly using casting operators
"Static type of the target is more specific
"object -> cl_abap_typedescr
tdo_super = CAST #( tdo_gen_obj ).
"cl_abap_typedescr -> cl_abap_datadescr
"Note: Here, the dynamic type of the source variable is cl_abap_elemdescr.
tdo_data = CAST #( tdo ).
"cl_abap_datadescr -> cl_abap_elemdescr
tdo_elem = CAST #( tdo_data ).
"cl_abap_typedescr -> cl_abap_elemdescr
tdo_elem = CAST #( tdo_super ).IF ... IS INSTANCE OF ... and CASE TYPE OF check the dynamic type of non-initial object reference variables and the static type of initial object reference variables.DATA type_descr_obj TYPE REF TO cl_abap_typedescr.
DATA type_descr_obj_gen TYPE REF TO object.
DATA str TYPE string.
"In the examples above, the assignments work. The following code snippets
"deal with examples in which a downcast is not possible. An exception is
"raised.
DATA str_table TYPE string_table.
DATA type_descr_obj_table TYPE REF TO cl_abap_tabledescr.
"With the following method call, type_descr_obj points to an object with
"reference to cl_abap_tabledescr.
type_descr_obj = cl_abap_typedescr=>describe_by_data( str_table ).
"Therefore, the following downcast works.
type_descr_obj_table = CAST #( type_descr_obj ).
"You could also achieve the same in one statement and with inline
"declaration.
DATA(type_descr_obj_table_2) = CAST cl_abap_tabledescr( cl_abap_typedescr=>describe_by_data( str_table ) ).
"Example for an impossible downcast
"The generic object reference variable points to cl_abap_elemdescr after the following
"assignment.
type_descr_obj_gen = cl_abap_typedescr=>describe_by_data( str ).
"Without catching the exception, the runtime error MOVE_CAST_ERROR
"occurs. There is no syntax error at compile time. The static type of
"type_descr_obj_gen is more generic than the static type of the target variable.
"The error occurs when trying to downcast, and the dynamic type is used.
TRY.
type_descr_obj_table = CAST #( type_descr_obj_gen ).
CATCH cx_sy_move_cast_error.
ENDTRY.
"Note: type_descr_obj_table sill points to the reference as assigned above after trying
"to downcast in the TRY control structure.
"Using CASE TYPE OF and IS INSTANCE OF statements, you can check if downcasts
"are possible.
"Note: In case of ...
"- non-initial object reference variables, the dynamic type is checked.
"- initial object reference variables, the static type is checked.
*&---------------------------------------------------------------------*
*& IS INSTANCE OF
*&---------------------------------------------------------------------*
DATA some_type_descr_obj TYPE REF TO cl_abap_typedescr.
some_type_descr_obj = cl_abap_typedescr=>describe_by_data( str_table ).
IF some_type_descr_obj IS INSTANCE OF cl_abap_elemdescr.
DATA(type_descr_obj_a) = CAST cl_abap_elemdescr( some_type_descr_obj ).
ELSE.
"This branch is executed. The downcast is not possible.
...
ENDIF.
IF some_type_descr_obj IS INSTANCE OF cl_abap_elemdescr.
DATA(type_descr_obj_b) = CAST cl_abap_elemdescr( some_type_descr_obj ).
ELSEIF some_type_descr_obj IS INSTANCE OF cl_abap_refdescr.
DATA(type_descr_obj_c) = CAST cl_abap_refdescr( some_type_descr_obj ).
ELSEIF some_type_descr_obj IS INSTANCE OF cl_abap_structdescr.
DATA(type_descr_obj_d) = CAST cl_abap_structdescr( some_type_descr_obj ).
ELSEIF some_type_descr_obj IS INSTANCE OF cl_abap_tabledescr.
"In this example, this branch is executed. With the check,
"you can make sure that the downcast is indeed possible.
DATA(type_descr_obj_e) = CAST cl_abap_tabledescr( some_type_descr_obj ).
ELSE.
...
ENDIF.
DATA initial_type_descr_obj TYPE REF TO cl_abap_typedescr.
IF initial_type_descr_obj IS INSTANCE OF cl_abap_elemdescr.
DATA(type_descr_obj_f) = CAST cl_abap_elemdescr( some_type_descr_obj ).
ELSEIF initial_type_descr_obj IS INSTANCE OF cl_abap_refdescr.
DATA(type_descr_obj_g) = CAST cl_abap_refdescr( some_type_descr_obj ).
ELSEIF initial_type_descr_obj IS INSTANCE OF cl_abap_structdescr.
DATA(type_descr_obj_h) = CAST cl_abap_structdescr( some_type_descr_obj ).
ELSEIF initial_type_descr_obj IS INSTANCE OF cl_abap_tabledescr.
DATA(type_descr_obj_i) = CAST cl_abap_tabledescr( some_type_descr_obj ).
ELSE.
"In this example, this branch is executed. The static
"type of the initial object reference variable is used,
"which is cl_abap_typedescr here.
...
ENDIF.
*&---------------------------------------------------------------------*
*& CASE TYPE OF
*&---------------------------------------------------------------------*
"The examples are desinged similarly to the IS INSTANCE OF examples.
DATA(dref) = REF #( str_table ).
some_type_descr_obj = cl_abap_typedescr=>describe_by_data( dref ).
CASE TYPE OF some_type_descr_obj.
WHEN TYPE cl_abap_elemdescr.
DATA(type_descr_obj_j) = CAST cl_abap_elemdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_refdescr.
"In this example, this branch is executed. With the check,
"you can make sure that the downcast is indeed possible.
DATA(type_descr_obj_k) = CAST cl_abap_refdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_structdescr.
DATA(type_descr_obj_l) = CAST cl_abap_structdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_tabledescr.
DATA(type_descr_obj_m) = CAST cl_abap_tabledescr( some_type_descr_obj ).
WHEN OTHERS.
...
ENDCASE.
"Example with initial object reference variable
CASE TYPE OF initial_type_descr_obj.
WHEN TYPE cl_abap_elemdescr.
DATA(type_descr_obj_n) = CAST cl_abap_elemdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_refdescr.
DATA(type_descr_obj_o) = CAST cl_abap_refdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_structdescr.
DATA(type_descr_obj_p) = CAST cl_abap_structdescr( some_type_descr_obj ).
WHEN TYPE cl_abap_tabledescr.
DATA(type_descr_obj_q) = CAST cl_abap_tabledescr( some_type_descr_obj ).
WHEN OTHERS.
"In this example, this branch is executed. The static
"type of the initial object reference variable is used,
"which is cl_abap_typedescr here.
...
ENDCASE.Interfaces ...
section of classes.
local and global interfaces.
polymorphism in classes. Each class that implements an interface can implement its methods differently. Interface reference variables can point to objects of all classes that implement the associated interface.
implementation part. The implementation is done in classes that use the interface.
DATA,CLASS-DATA, METHODS, CLASS-METHODS, are possible. Constructors are not possible.
PUBLIC addition. "The addition PUBLIC is for global interfaces
INTERFACE intf_global PUBLIC.
"Local interface
"INTERFACE intf_local.
DATA ...
CLASS-DATA ...
METHODS ...
CLASS-METHODS ...
CONSTANTS ...
TYPES ...
ENDINTERFACE.DEFAULT IGNORE or DEFAULT FAIL (see next section).... intf~comp ...."Local interface in a CCIMP include
INTERFACE lif.
DATA str TYPE string.
CLASS-DATA number TYPE i.
CONSTANTS const_number TYPE i VALUE 1.
"All of the following methods must be implemented in classes
"that implement the interface.
METHODS inst_meth IMPORTING num TYPE i.
CLASS-METHODS stat_meth RETURNING VALUE(result) TYPE string.
ENDINTERFACE.
"Local class in a CCIMP include implementing the interface
CLASS lcl DEFINITION.
PUBLIC SECTION.
"Multiple interface implementations are possible
INTERFACES lif.
ENDCLASS.
CLASS lcl IMPLEMENTATION.
METHOD lif~inst_meth.
...
"Assuming lif~number has been assigned a value somewhere.
DATA(addition) = num + lif~number.
...
ENDMETHOD.
METHOD lif~stat_meth.
...
ENDMETHOD.
ENDCLASS.
**********************************************************************
"Including interfaces in other interfaces
INTERFACE lif2.
METHODS meth_of_lif2.
INTERFACES lif.
ENDINTERFACE.
CLASS lcl2 DEFINITION.
PUBLIC SECTION.
INTERFACES lif2.
ENDCLASS.
CLASS lcl2 IMPLEMENTATION.
METHOD lif2~meth_of_lif2.
...
ENDMETHOD.
METHOD lif~inst_meth.
...
ENDMETHOD.
METHOD lif~stat_meth.
...
ENDMETHOD.
ENDCLASS.[!NOTE] The code examples show local classes and interfaces declared, for example, in the CCIMP include of a class pool.
| Addition | Notes |
|
Specifies alias names for the interface components. The components can then be addressed using the alias name. | |
| |
|
See above. With this addition, all methods are specified as abstract. | |
|
Specifies methods as final so they cannot be further redefined. Multiple methods can be specified. | |
|
See above. With this addition, all methods are specified as final. | |
| |
| |
|
|
|
|
|
See above. The behavior with this addition is that when an unimplemented method is called, the |
DATA i_ref TYPE REF TO intf.Addressing interface components:
i_ref->attri_ref->meth( )cl_ref->intf~attrcl_ref->intf~methclass=>intf~attr,class=>intf~meth( )intf=>const"----------------------- Syntax patterns -----------------------
"Addressing instance interface components using interface reference variable
DATA i_ref TYPE REF TO intf.
DATA cl_ref TYPE REF TO class.
"Creating an instance of a class that implements the interface intf
cl_ref = NEW #( ).
"If the class class implements an interface intf,
"the class reference variable cl_ref can be assigned
"to the interface reference variable i_ref.
"The reference in i_ref then points to the same object
"as the reference in cl_ref.
i_ref = cl_ref.
"Can also be done directly, i. e. directly creating an object to which the interface reference variable points
i_ref = NEW class( ).
"Instance interface method via interface reference variable
... i_ref->inst_method( ... ) ...
"Instance interface attribute via interface reference variable
... i_ref->inst_attr ...
"Addressing instance components using the class reference variable
"is also possible but it's not the recommended way.
... cl_ref->intf~inst_method( ... ) ...
... cl_ref->intf~inst_attr ...
"Addressing static interface components
"class=> can be dropped if the method is called in the same class that implements the interface
... class=>intf~stat_method( ... ) ...
... class=>intf~stat_attr ...
"Just for the record: Static interface components can be called via reference variables, too.
... i_ref->stat_method( ... ) ...
... i_ref->stat_attr ...
... cl_ref->intf~stat_method( ... ) ...
"Constants
"A constant can be addressed using the options mentioned above.
"Plus, it can be addressed using the following pattern
... intf=>const ...Example using local interfaces and classes
INTERFACE lif.
METHODS inst_meth.
CLASS-METHODS stat_meth.
TYPES c1 TYPE c LENGTH 1.
DATA inst_num TYPE i.
CLASS-DATA stat_str TYPE string.
CONSTANTS const TYPE string VALUE `ABAP`.
ENDINTERFACE.
CLASS lcl1 DEFINITION.
PUBLIC SECTION.
INTERFACES lif.
ENDCLASS.
CLASS lcl1 IMPLEMENTATION.
METHOD lif~inst_meth.
...
ENDMETHOD.
METHOD lif~stat_meth.
...
ENDMETHOD.
ENDCLASS.
"This class demonstrates addressing interface components
CLASS lcl2 DEFINITION.
PUBLIC SECTION.
CLASS-METHODS meth.
DATA flag TYPE lif=>c1.
ENDCLASS.
CLASS lcl2 IMPLEMENTATION.
METHOD meth.
"Addressing instance interface components using interface reference variable
"Interface reference variable
DATA i_ref TYPE REF TO lif.
"Object reference variable
DATA cl_ref TYPE REF TO lcl1.
"Creating an instance of a class that implements the interface lif
cl_ref = NEW #( ).
"If the class lcl1 implements the interface lif,
"the class reference variable cl_ref can be assigned
"to the interface reference variable i_ref.
"The reference in i_ref then points to the same object
"as the reference in cl_ref.
i_ref = cl_ref.
"This can also be done directly, i. e. directly creating an object to
"which the interface reference variable points
DATA i_ref2 TYPE REF TO lif.
i_ref2 = NEW lcl1( ).
"Instance interface method via interface reference variable
i_ref->inst_meth( ).
"Instance interface attribute via interface reference variable
DATA(a) = i_ref->inst_num.
"Addressing instance components using the class reference variable
"is also possible but it is not the recommended way.
cl_ref->lif~inst_meth( ).
DATA(b) = cl_ref->lif~inst_num.
"Addressing static interface components
"The class name and => can be dropped if the method is called in the
"same class that implements the interface.
lcl1=>lif~stat_meth( ).
DATA(c) = lcl1=>lif~stat_str.
"Note: Static interface components can be called via reference variables, too.
i_ref->stat_meth( ).
DATA(d) = i_ref->stat_str.
cl_ref->lif~stat_meth( ).
"Constants
"A constant can be addressed using the options mentioned above.
"Plus, it can be addressed using the pattern intf=>...
DATA(e) = lif=>const.
DATA(f) = i_ref->const.
DATA(g) = cl_ref->lif~const.
"Types
DATA h TYPE lif=>c1.
"Referring to attributes in the interface
DATA i LIKE lif=>const.
ENDMETHOD.
ENDCLASS.Expand the following collapsible section for example code. To try the example out, create a demo interface named zif_some_interface and a demo class named zcl_demo_abap. If they already exist, reuse them. Otherwise, create new artifacts with different names. Paste the code into them. If you choose a different names, update the names in the code snippet accordingly. After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console.
🟢 Click to expand for more information and example code
Example interface:
INTERFACE zif_some_interface
PUBLIC .
TYPES c3 type c length 3.
DATA add_result TYPE i.
CLASS-DATA: subtr_result TYPE i.
METHODS addition IMPORTING num1 TYPE i
num2 TYPE i.
CLASS-METHODS subtraction IMPORTING num1 TYPE i
num2 TYPE i.
METHODS meth_ignore DEFAULT IGNORE returning value(int) type i.
METHODS meth_fail DEFAULT FAIL returning value(int) type i.
ENDINTERFACE.When you have activated the interface, create the class. The following steps comment on various things.
Example class implementations:
1)
INTERFACES zif_some_interface. to the public visibility section.DEFAULT IGNORE and DEFAULT FAIL are not automatically added. If implementations are desired, you can manually add the implementations for these methods. See the following step.if_oo_adt_classrun.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_some_interface.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
ENDMETHOD.
METHOD zif_some_interface~addition.
ENDMETHOD.
METHOD zif_some_interface~subtraction.
ENDMETHOD.
ENDCLASS.2)
DEFAULT IGNORE and DEFAULT FAIL.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_some_interface.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
ENDMETHOD.
METHOD zif_some_interface~addition.
ENDMETHOD.
METHOD zif_some_interface~subtraction.
ENDMETHOD.
METHOD zif_some_interface~meth_fail.
ENDMETHOD.
METHOD zif_some_interface~meth_ignore.
ENDMETHOD.
ENDCLASS.3)
DEFAULT IGNORE and DEFAULT FAIL are intentionally not implemented, but the methods are nevertheless called. DEFAULT IGNORE: No implementation available, and no value is assigned for the returning parameter. Therefore, the value is initial. DEFAULT FAIL: If the exception is not caught, a runtime error occurs.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
INTERFACES zif_some_interface.
ALIASES res FOR zif_some_interface~add_result.
ALIASES add FOR zif_some_interface~addition.
ALIASES subtr FOR zif_some_interface~subtraction.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
"Examples using an object reference variable
DATA(oref) = NEW zcl_demo_abap( ).
oref->add( num1 = 1 num2 = 2 ).
DATA(res1) = oref->res.
out->write( res1 ).
oref->subtr( num1 = 1 num2 = 2 ).
DATA(res2) = oref->zif_some_interface~subtr_result.
out->write( res2 ).
"Referring to a type declared in the interface
DATA char_a TYPE zif_some_interface~c3.
DATA char_b TYPE zif_some_interface=>c3.
"Calling non-implemented methods
DATA(int_ig_a) = oref->zif_some_interface~meth_ignore( ).
ASSERT int_ig_a = 0.
TRY.
DATA(int_fl_a) = oref->zif_some_interface~meth_fail( ).
CATCH cx_sy_dyn_call_illegal_method INTO DATA(error).
out->write( error->get_text( ) ).
ENDTRY.
"Similar examples using an interface reference variable
DATA iref TYPE REF TO zif_some_interface.
iref = NEW zcl_demo_abap( ).
iref->addition( num1 = 3 num2 = 5 ).
DATA(res3) = iref->add_result.
out->write( res3 ).
iref->subtraction( num1 = 3 num2 = 5 ).
DATA(res4) = iref->subtr_result.
out->write( res4 ).
"Referring to a type declared in the interface
DATA char_c TYPE iref->c3.
"Calling non-implemented methods
DATA(int_ig_b) = iref->meth_ignore( ).
ASSERT int_ig_b = 0.
TRY.
DATA(int_fl_b) = iref->meth_fail( ).
CATCH cx_sy_dyn_call_illegal_method INTO error.
out->write( error->get_text( ) ).
ENDTRY.
ENDMETHOD.
METHOD add.
res = num1 + num2.
ENDMETHOD.
METHOD subtr.
zif_some_interface~subtr_result = num1 - num2.
ENDMETHOD.
ENDCLASS.tests](https://help.sap.com/doc/abapdocu_cp_index_htm/CLOUD/en-US/index.htm?file=abenunit_test_glosry.htm "Glossary Entry") if you want to test private methods.
READ-ONLY.a grants friendship to class b, class b must also explicitly grant friendship to class a so that a can access the invisible components of class b.FRIENDS: For local classes, e.g. local classes granting friendship to other local classes or the global class of the class poolGLOBAL FRIENDS: Used in global classes to grant friendship to other global classes and interfacesLOCAL FRIENDS: Used for global classes to grant friendship to local classes and interfaces in its own class pool; however, it is a dedicated statement, as shown in the example below (the declaration CLASS zcl_demo_abap DEFINITION LOCAL FRIENDS local_class. in the CCDEF include) You specify the befriended class in the definition part using a FRIENDS addition:
"For local classes. Friendship can be granted to all classes/interfaces
"of the same program and the class library.
"Multiple classes can be specified as friends.
CLASS lo_class DEFINITION FRIENDS other_class ... .
...
CLASS lo_class DEFINITION CREATE PRIVATE FRIENDS other_class ... .
"Addition GLOBAL only allowed for global classes, i. e. if the addition PUBLIC is also used
"Other global classes and interfaces from the class library can be specified after GLOBAL FRIENDS.
CLASS global_class DEFINITION CREATE PUBLIC FRIENDS other_global_class ... .Expand the following collapsible section for an example class. It demonstrates granting friendship between a global class and a local class (in the CCIMP include, Local Types tab in ADT). In the example, friendship is granted in both ways so that the global class can access private components of the local class, and the local class can access private components of the global class. For more information, see the following topics:
🟢 Click to expand for more information and example code
| Class include | Code |
|
Global class |
|
|
CCDEF include (Class-relevant Local Types tab in ADT) |
|
|
CCIMP include (Local Types tab in ADT) |
|
High-level steps involved:
Events
EVENTS statement.CLASS-EVENTS.EXPORTING and formal parameters specifying passing by value) for an event. When the event is raised, actual parameters are transferred to event handlers.sender, which is a reference variable that automatically assigns the raising object. "Declaration part of a class/interface
"Instance events
EVENTS: i_evt1,
"Events can only have output parameters that are passed by value
i_evt2 EXPORTING VALUE(num) TYPE i ...
...
"Static events
CLASS-EVENTS: st_evt1,
st_evt2 EXPORTING VALUE(num) TYPE i ...Event handlers
RAISE EVENT statement in either another method or the same method.RAISE EVENT rather than through direct method calls.SET HANDLER statement.FOR EVENT some_event OF cl|intf syntax for event handler declarations.some_event is an instance event, the event handler can manage events for all objects of class cl, its subclasses, or objects implementing the interface intf.some_event is a static event, the event handler can manage events for class cl, its subclasses, or any classes implementing the interface intf.ABSTRACT and FINAL for instance methods, and DEFAULT IGNORE or DEFAULT FAIL for both instance and static methods.IMPORTING in the declaration to define input parameters.EXPORTING in the declared event.TYPE, LIKE, OPTIONAL, or DEFAULT. The properties will be inherited from the specified event parameters.some_event is an instance event, you can specify the sender formal parameter, which is an implicit output parameter for each instance event, providing a reference to the object that raised the event. "Event handlers for instance events
METHODS: handler_meth1 FOR EVENT i_evt1 OF some_class,
"Parameter names must be the same as declared;
"no further additions possible for the parameter (e.g. TYPE);
"the predefined, implicit parameter sender as another formal parameter is possible with instance events,
"it is typed as a reference variable, which itself has the class/interface as a static type,
"If the event handler is called by an instance event, it is passed a reference to the raising object in sender.
handler_meth2 FOR EVENT i_evt2 OF some_class IMPORTING num sender,
...Registering and deregistering event handlers
SET HANDLER handler1 handler2 ... FOR oref|ALL INSTANCES [ACTIVATION act].handler1, etc. can be specified as follows: meth (methods from the same or other classes defined as instance event handlers; event handlers for static events cannot be specified), oref->meth, class=>methFOR oref: (De)registers event handlers for a single object.FOR ALL INSTANCES: (De)registers the event handlers for all instances.ACTIVATION: Used to (de)register event handlers; expects a single-character text field. The default value is X (indicating registration; so, the addition is optional for registration). A blank value means it is deregistered.SET HANDLER handler1 handler2 ... [ACTIVATION act].SET HANDLER statements set the system field sy-subrc. See the example.Raising events
RAISE EVENT statements, which can only occur within methods.EXPORTING addition (RAISE EVENT some_event EXPORTING a = b c = d ...) to pass actual parameters to event handlers.sender is declared for an event handler, it automatically receives a reference to the raising object when instance events are triggered. However, sender cannot be explicitly specified or assigned here.[!NOTE] In RAP, special RAP business events are available. They can be raised in ABAP behavior pools with RAISE ENTITY EVENT statements. Find more information in the ABAP for RAP: Entity Manipulation Language (ABAP EML) cheat sheet.
Expand the following collapsible section for example code. To try it out, create a demo class named zcl_demo_abap. If it already exists, reuse it. Otherwise, create a new class with a different name. Paste the code into it. If you choose a different class name, update the class name in the code snippet accordingly. Note that the example includes code in the global class and the CCIMP include (Local Types tab in ADT). After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console. For more information on the example, see the inline comments.
🟢 Click to expand for example code
| Class include | Code |
|
Global class |
|
|
CCIMP include (Local Types tab in ADT) |
|
Find ABAP examples of design patterns in object-oriented programming in this ABAP cheat sheet.
EXCEPTIONS addition, which should not be specified anymore for new developments, raising classic, non-class based exceptions. "ABAP class (creates UUIDs) raising a class-based exception
TRY.
DATA(uuid) = cl_system_uuid=>create_uuid_x16_static( ).
CATCH cx_uuid_error.
ENDTRY.
"ABAP class (provides type information, see the Dynamic Programming cheat sheet) specified with the EXCEPTIONS addition raising a non-class based exception
cl_abap_typedescr=>describe_by_name( EXPORTING p_name = `TYPE_THAT_DOES_NOT_EXIST`
RECEIVING p_descr_ref = DATA(tdo1)
EXCEPTIONS type_not_found = 4 ).
IF sy-subrc <> 0.
"Type not found
...
ENDIF.
cl_abap_typedescr=>describe_by_name( EXPORTING p_name = `ABAP_BOOLEAN`
RECEIVING p_descr_ref = DATA(tdo2)
EXCEPTIONS type_not_found = 4 ).
ASSERT sy-subrc = 0."!. @parameter | ... for parameters and @raising | ... for declared exceptions."! <p class="shorttext">Demo ABAP Doc comments</p>
"!
"! <p>This class serves as an example to illustrate comments for ABAP Doc.
"! The comments begin with the string <strong>"!</strong>, a special form of regular comments introduced by <strong>"</strong>. <br/><br/>
"! The {@link zcl_demo_abap.METH:calculate} method of the example class performs a calculation. </p>
"! <h2>Notes</h2>
"! <ul>
"! <li>ABAP Doc documents declarations in ABAP programs.</li>
"! <li>The ABAP development tools for Eclipse (ADT) support ABAP Doc.</li>
"! <li>The content of ABAP Doc comments is converted to HTML and displayed appropriately.</li>
"! <li>Check out the supported HTML tags by choosing <em>CTRL + Space</em> after <em>"!</em>. h1 - h3 tags can also be used.</li>
"! <li>Escaping special characters: <strong>", ', <, >, @, {, |, and }</strong></li>
"! </ul>
"! <h2>Steps</h2>
"! <ol>
"! <li>Create a demo class named <em>zcl_demo_abap</em></li>
"! <li>Copy and paste the code of this example and activate.</li>
"! <li>Click the class name to display the comments in the <em>ABAP Element Info</em> ADT tab.</li>
"! <li>You can also choose F2 for the class name to display the information.</li>
"! </ol>
"! <h3>More examples</h3>
"! Find more code examples in ABAP cheat sheet demo classes, such as {@link zcl_demo_abap_objects} and others. <br/>
"! <h3>Link examples</h3>
"! <ul>
"! <li>Repository objects such as the following, and more:
"! <ul><li>Classes, e.g. {@link zcl_demo_abap}</li>
"! <li>Interfaces, e.g. {@link if_oo_adt_classrun}</li>
"! <li>CDS artifacts, e.g. {@link i_apisforclouddevelopment}</li>
"! <li>DDIC database tables, e.g. {@link zdemo_abap_carr}</li>
"! <li>DDIC data elements, e.g. {@link land1}</li></ul>
"! <li>Method: {@link zcl_demo_abap.METH:calculate}</li>
"! <li>Constant: {@link zcl_demo_abap.DATA:const}</li>
"! <li>Data object: {@link zcl_demo_abap.DATA:dobj}</li>
"! <li>Method parameter: {@link zcl_demo_abap.METH:calculate.DATA:operator}</li>
"! <li>Interface implemented in a class: {@link zcl_demo_abap.INTF:if_oo_adt_classrun}</li>
"! <li>Interface method implemented in a class: {@link zcl_demo_abap.INTF:if_oo_adt_classrun.METH:main}</li>
"! <li>DDIC domain: {@link DOMA:land1}</li>
"! <li>XSLT: {@link XSLT:id}</li>
"! </ul>
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
TYPES: basetype TYPE c LENGTH 1,
BEGIN OF ENUM t_enum_calc STRUCTURE en_calc BASE TYPE basetype,
init VALUE IS INITIAL,
plus VALUE '+',
minus VALUE '-',
multiply VALUE '*',
divide VALUE '/',
END OF ENUM t_enum_calc STRUCTURE en_calc.
"! <p>This method performs a calculation.</p>
"! @parameter num1 | First number for the calcation
"! @parameter num2 | Second number for the calcation
"! @parameter operator | Operator. Only one of the four operators +, -, *, / is allowed.
"! The value is represented by an enumerated type. Note that there is no handling if
"! the assigned value is initial.
"! @parameter result | Result of the calculation
"! @raising cx_sy_zerodivide | Zero division
"! @raising cx_sy_arithmetic_overflow | Arithmetic overflow
CLASS-METHODS calculate IMPORTING num1 TYPE i
num2 TYPE i
operator TYPE t_enum_calc
RETURNING VALUE(result) TYPE decfloat34
RAISING cx_sy_zerodivide cx_sy_arithmetic_overflow.
"! This is an ABAP Doc comment for a constant
CONSTANTS const TYPE i VALUE 123.
"! This is an ABAP Doc comment for a static attribute of a class
CLASS-DATA dobj TYPE i.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA(result_plus) = calculate( num1 = 1 num2 = 10 operator = en_calc-plus ).
DATA(result_minus) = calculate( num1 = 1 num2 = 10 operator = en_calc-minus ).
DATA(result_multiply) = calculate( num1 = 2 num2 = 5 operator = en_calc-multiply ).
DATA(result_divide) = calculate( num1 = 10 num2 = 5 operator = en_calc-divide ).
out->write( data = result_plus name = `result_plus` ).
out->write( data = result_minus name = `result_minus` ).
out->write( data = result_multiply name = `result_multiply` ).
out->write( data = result_divide name = `result_divide` ).
ENDMETHOD.
METHOD calculate.
result = SWITCH #( operator
WHEN en_calc-plus THEN num1 + num2
WHEN en_calc-minus THEN num1 - num2
WHEN en_calc-multiply THEN num1 * num2
WHEN en_calc-divide THEN num1 / num2
ELSE '0' ).
ENDMETHOD.
ENDCLASS.DATA or FINAL on the left side of an assignment with the = operator. In these cases, do not use the @variable syntax, as the ABAP Doc comment automatically associates with the declared variable.ASSIGN statements, can include ABAP Doc comments (currently excluding ABAP SQL). These comments should be placed immediately before the statement and explicitly reference the variable name using the @variable syntax. For method calls involving multiple inline declarations, you can define ABAP Doc comments with multiple @variable specifications, each referring to a specific actual parameter."! Calculation result
DATA(result1) = 1 + 3.
"! <p>Calculation result<br>
"! This is a link to { @link .DATA:result1 }</p>
FINAL(result2) = 6 - 2.
"ABAP Doc comments for actual paramters declared inline
TRY.
"! 16 Byte System UUID in Binary Format
DATA(uuid_x16) = cl_system_uuid=>create_uuid_x16_static( ).
"! @variable c22 | 16 Byte System UUID in Base64
"! @variable c32 | 16 Byte System UUID in Base32
"! @variable c26 | 16 Byte System UUID in Hex Format
"! @variable c36 | 16 Byte System UUID in RFC4122 Format
cl_system_uuid=>convert_uuid_x16_static(
EXPORTING
uuid = uuid_x16
IMPORTING
uuid_c22 = FINAL(c22)
uuid_c32 = FINAL(c32)
uuid_c26 = FINAL(c26)
uuid_c36 = FINAL(c36) ).
CATCH cx_uuid_error.
ENDTRY.
"! Demo string table
DATA(str_table) = VALUE string_table( ( `AB,AP` ) ( `Hel,lo` )
( `Wor,ld` ) ).
"! @variable <line> | Table line assigned to field symbol
LOOP AT str_table ASSIGNING FIELD-SYMBOL(<line>).
"! @variable split1 | First split result
"! @variable split2 | Second split result
SPLIT <line> AT ',' INTO DATA(split1) FINAL(split2).
ENDLOOP.
"! @variable dref | Table line referenced via a data reference variable
LOOP AT str_table REFERENCE INTO DATA(dref).
...
ENDLOOP.! characters specified before operands, particularly in signatures of procedures.The following nonsensical example shows various specifications with the escape character that emphasize in the program that the operands are not to be confused with ABAP words. These specifications are not mandatory in the example. The example only addresses escape characters you may encounter in (older) ABAP code.
CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
DATA num TYPE i.
CLASS-DATA default TYPE i VALUE 1.
METHODS meth1 IMPORTING !num TYPE i.
METHODS !methods IMPORTING !raising TYPE i OPTIONAL
!optional TYPE i
!exporting TYPE i
EXPORTING !importing TYPE i
!changing TYPE i
CHANGING !default TYPE i.
PROTECTED SECTION.
PRIVATE SECTION.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
meth1( 1 ).
DATA !exporting TYPE i.
DATA !changing TYPE i.
methods(
EXPORTING
raising = 1
optional = 5
exporting = 10
IMPORTING
importing = !exporting
changing = !changing
CHANGING
default = !default
).
ENDMETHOD.
METHOD meth1.
DATA(a) = num.
DATA(b) = me->num.
DATA(c) = !num.
me->num = num.
me->num = !num.
ENDMETHOD.
METHOD methods.
!importing = !raising + !optional.
!changing = !exporting.
!default += 1.
importing = raising + optional.
changing = exporting.
default += 1.
ENDMETHOD.
ENDCLASS.The following example highlights potential pitfalls regarding name shadowing in ABAP. It occurs in ABAP Objects when a local variable or parameter shares the same name as, for example, a variable specified in a visibility section. It can also happen with type and method naming. This overlap can cause confusion and may lead to errors if the wrong variable is referenced unintentionally. The following nonsensical example illustrates these pitfalls.
Expand the following collapsible section for example code. To try it out, create a demo class named zcl_demo_abap, or reuse it if it already exists. Paste the code into it. If you choose a different class name, update the class name in the code snippet accordingly. Note that the example includes code in the global class and the CCIMP include (Local Types tab in ADT). After activation, choose F9 in ADT to execute the class. The example is set up to display output in the console. Note the comments in the code.
🟢 Click to expand for example code
| Class include | Code |
|
Global class |
|
|
CCIMP include (Local Types tab in ADT) |
|
This section outlines special rules for using constructor expressions with COND/SWITCH and # when passing actual parameters to generic formal parameters.
... meth( some_param = COND #( ... THEN ... ) ) ...When using # for the operand type, the following rules apply for type inference:
THEN is known statically and matches the formal parameter's generic type, that data type will be used.string is derived for csequence and clike. For more information, see here.The following example class demonstrates this behavior:
THEN is known statically and matches the generic formal parameter type. This type is used for all subsequent THEN branches.csequence.THEN is c LENGTH 5, so all other THEN branches use this type. For example, the result for c10, which is of type c LENGTH 10 with the value '1234567890', is '12345'.CASE statement and contrasts with example 1.SWITCH and includes an importing parameter of type numeric. THEN is p LENGTH 8 DECIMALS 2, so all other THEN branches use this type. For example, the integer value -123 is converted to -123.00. COND with an importing parameter of type clike.THEN does not match the generic type. The example uses a demo data object of type decfloat34 for the assignment.clike, the type string is automatically derived by default (which also applies to csequence). Consequently, all other THEN branches use this type.g represents type string, C indicates type c, and P signifies type p.CLASS zcl_demo_abap DEFINITION
PUBLIC
FINAL
CREATE PUBLIC .
PUBLIC SECTION.
INTERFACES if_oo_adt_classrun.
PROTECTED SECTION.
PRIVATE SECTION.
METHODS meth1 IMPORTING input TYPE csequence
RETURNING VALUE(result) TYPE string.
METHODS meth2 IMPORTING input TYPE numeric
RETURNING VALUE(result) TYPE string.
METHODS meth3 IMPORTING input TYPE clike
RETURNING VALUE(result) TYPE string.
ENDCLASS.
CLASS zcl_demo_abap IMPLEMENTATION.
METHOD if_oo_adt_classrun~main.
DATA result TYPE string.
out->write( `------ Example 1 ------` ).
DATA str TYPE string VALUE `abcdefghijklmnopqrstuvwxyz`.
DATA c5 TYPE c LENGTH 5 VALUE 'hello'.
DATA c10 TYPE c LENGTH 10 VALUE '1234567890'.
DATA n7 TYPE n LENGTH 7 VALUE '1234567'.
DATA int TYPE i VALUE -123.
DO 5 TIMES.
result = meth1( COND #( WHEN sy-index = 1 THEN c5
WHEN sy-index = 2 THEN c10
WHEN sy-index = 3 THEN n7
WHEN sy-index = 4 THEN str
WHEN sy-index = 5 THEN int ) ).
out->write( result ).
ENDDO.
out->write( |\n| ).
out->write( `------ Example 2 ------` ).
DO 5 TIMES.
CASE sy-index.
WHEN 1.
result = meth1( c5 ).
out->write( result ).
WHEN 2.
result = meth1( c10 ).
out->write( result ).
WHEN 3.
"result = meth1( n5 ).
WHEN 4.
result = meth1( str ).
out->write( result ).
WHEN 5.
"result = meth1( int ).
ENDCASE.
ENDDO.
out->write( |\n| ).
out->write( `------ Example 3 ------` ).
DATA d34 TYPE decfloat34 VALUE '1.0234'.
DATA d16 TYPE decfloat16 VALUE '9.8765'.
DATA integer TYPE i VALUE -123.
DATA packed TYPE p LENGTH 8 DECIMALS 2 VALUE '1.23'.
str = `112.5243`.
DO 5 TIMES.
result = meth2( SWITCH #( sy-index WHEN 1 THEN packed
WHEN 2 THEN integer
WHEN 3 THEN d34
WHEN 4 THEN d16
WHEN 5 THEN str ) ).
out->write( result ).
ENDDO.
out->write( |\n| ).
out->write( `------ Example 4 ------` ).
d34 = '1.0234'.
d16 = '9.876526548964654'.
integer = -1234567890.
packed = '-12345.67'.
DO 4 TIMES.
"Note: The code inlcudes a pragma to suppress a syntax warning since the
"compiler can detect that the operand's data type after the first THEN
"does not match the generic type
result = meth3( COND #( WHEN sy-index = 1 THEN d34
WHEN sy-index = 2 THEN d16
WHEN sy-index = 3 THEN integer
WHEN sy-index = 4 THEN packed ) ) ##TYPE.
out->write( result ).
ENDDO.
ENDMETHOD.
METHOD meth1.
DATA(t) = CAST cl_abap_datadescr( cl_abap_typedescr=>describe_by_data( input ) )->type_kind.
result = |Value: "{ input }"; type: { t }|.
ENDMETHOD.
METHOD meth2.
DATA(t) = CAST cl_abap_datadescr( cl_abap_typedescr=>describe_by_data( input ) )->type_kind.
result = |Value: "{ input }"; type: { t }|.
ENDMETHOD.
METHOD meth3.
DATA(t) = CAST cl_abap_datadescr( cl_abap_typedescr=>describe_by_data( input ) )->type_kind.
result = |Value: "{ input }"; type: { t }|.
ENDMETHOD.
ENDCLASS.You can check the subtopics of
in the ABAP Keyword Documentation.
[!NOTE] - The steps to import and run the code are outlined here. - Disclaimer
04_ABAP_Object_Orientation.md。版权归原作者所有。