Datenreferenzen in ABAP sind typisierte Zeiger (Pointer), die auf Datenobjekte im Speicher verweisen. Im Gegensatz zu Field-Symbols, die direkt auf Speicher zeigen, sind Datenreferenzen eigenständige Variablen, die eine Adresse speichern.
Grundkonzept
- Eine Datenreferenz ist eine Variable, die die Speicheradresse eines Datenobjekts enthält
- Sie kann weitergegeben, gespeichert und verglichen werden
- Der Zugriff auf die Daten erfolgt über Dereferenzierung (
->*) - Datenreferenzen können initial (NULL) sein
Syntax
Datenreferenz deklarieren
" Typisierte ReferenzDATA: lr_data TYPE REF TO <datentyp>.
" Generische Referenz (auf beliebige Daten)DATA: lr_any TYPE REF TO data.
" Inline-DeklarationDATA(lr_inline) = REF #( variable ).Referenz erstellen
" Modern (ab 7.40): REF #()lr_data = REF #( variable ).
" Klassisch: GET REFERENCEGET REFERENCE OF variable INTO lr_data.
" Neues Datenobjekt erzeugenCREATE DATA lr_data TYPE <typ>.lr_data = NEW #( ). " Ab 7.40Dereferenzierung
" Zugriff auf die Daten<wert> = lr_data->*.
" Bei Strukturen: Komponentenzugriff<wert> = lr_struct->comp_name.
" Bei Tabellen: Zugriff auf ZeilenLOOP AT lr_table->* INTO DATA(ls_line). ...ENDLOOP.Systemfelder
Nach Operationen mit Datenreferenzen:
- Referenz
IS BOUND: Zeigt auf gültige Daten - Referenz
IS INITIAL: Zeigt auf nichts (NULL)
Beispiele
1. Grundlegende Verwendung
DATA: lv_number TYPE i VALUE 42.DATA: lr_number TYPE REF TO i.
" Referenz auf Variable erstellenlr_number = REF #( lv_number ).
" Dereferenzierung: Wert lesenWRITE: / 'Wert:', lr_number->*. " 42
" Dereferenzierung: Wert ändernlr_number->* = 100.WRITE: / 'Original:', lv_number. " 100 (geändert!)2. Referenz prüfen
DATA: lr_data TYPE REF TO string.
" Prüfen, ob Referenz gültig istIF lr_data IS BOUND. WRITE: / 'Referenz zeigt auf:', lr_data->*.ELSE. WRITE: / 'Referenz ist NULL'.ENDIF.
IF lr_data IS INITIAL. WRITE: / 'Referenz nicht initialisiert'.ENDIF.
" Referenz freigebenFREE lr_data.3. GET REFERENCE (klassische Syntax)
DATA: lv_text TYPE string VALUE 'Hallo Welt'.DATA: lr_text TYPE REF TO string.
" Klassische SyntaxGET REFERENCE OF lv_text INTO lr_text.
WRITE: / lr_text->*. " Hallo Welt4. Neues Datenobjekt erzeugen
DATA: lr_number TYPE REF TO i.
" Klassisch: CREATE DATACREATE DATA lr_number.lr_number->* = 42.
" Modern: NEW #()DATA(lr_string) = NEW string( 'Neuer String' ).WRITE: / lr_string->*.
" Mit TypDATA: lr_any TYPE REF TO data.CREATE DATA lr_any TYPE i.
" Generisch mit dynamischem TypDATA: lv_typename TYPE string VALUE 'STRING'.CREATE DATA lr_any TYPE (lv_typename).5. Referenzen mit internen Tabellen
TYPES: BEGIN OF ty_customer, id TYPE i, name TYPE string, END OF ty_customer.
DATA: lt_customers TYPE TABLE OF ty_customer, lr_table TYPE REF TO ty_customer.
lt_customers = VALUE #( ( id = 1 name = 'Müller' ) ( id = 2 name = 'Schmidt' )).
" REFERENCE INTO im LOOPLOOP AT lt_customers REFERENCE INTO lr_table. WRITE: / lr_table->id, lr_table->name.
" Änderung über Referenz lr_table->name = to_upper( lr_table->name ).ENDLOOP.
" READ TABLE mit REFERENCE INTOREAD TABLE lt_customers REFERENCE INTO lr_table WITH KEY id = 1.
IF sy-subrc = 0. lr_table->name = 'Geändert'.ENDIF.6. Referenzen in Tabellen speichern
DATA: lt_refs TYPE TABLE OF REF TO string.DATA: lv_str1 TYPE string VALUE 'Eins', lv_str2 TYPE string VALUE 'Zwei', lv_str3 TYPE string VALUE 'Drei'.
" Referenzen sammelnAPPEND REF #( lv_str1 ) TO lt_refs.APPEND REF #( lv_str2 ) TO lt_refs.APPEND REF #( lv_str3 ) TO lt_refs.
" Referenzen durchlaufenLOOP AT lt_refs INTO DATA(lr_str). WRITE: / lr_str->*.ENDLOOP.
" Originalwerte über Referenzen ändernREAD TABLE lt_refs INTO lr_str INDEX 1.lr_str->* = 'GEÄNDERT'.WRITE: / lv_str1. " GEÄNDERT7. Referenzen an Methoden übergeben
CLASS lcl_processor DEFINITION. PUBLIC SECTION. METHODS: process_data IMPORTING ir_data TYPE REF TO i.ENDCLASS.
CLASS lcl_processor IMPLEMENTATION. METHOD process_data. IF ir_data IS BOUND. ir_data->* = ir_data->* * 2. ENDIF. ENDMETHOD.ENDCLASS.
" VerwendungDATA: lv_value TYPE i VALUE 50, lo_proc TYPE REF TO lcl_processor.
lo_proc = NEW #( ).lo_proc->process_data( REF #( lv_value ) ).
WRITE: / lv_value. " 1008. Generische Referenzen (REF TO data)
DATA: lr_any TYPE REF TO data.FIELD-SYMBOLS: <fs_data> TYPE any.
" Referenz auf IntegerDATA(lv_int) = 42.lr_any = REF #( lv_int ).
" Für den Zugriff: Field-Symbol zuweisenASSIGN lr_any->* TO <fs_data>.WRITE: / <fs_data>.
" Referenz auf StringDATA(lv_str) = |Hallo|.lr_any = REF #( lv_str ).
ASSIGN lr_any->* TO <fs_data>.WRITE: / <fs_data>.9. Dynamische Objekterzeugung
DATA: lr_data TYPE REF TO data, lv_type TYPE string VALUE 'STRING'.
" Dynamisch Datenobjekt erzeugenCREATE DATA lr_data TYPE (lv_type).
" Wert zuweisen über Field-SymbolFIELD-SYMBOLS: <fs> TYPE any.ASSIGN lr_data->* TO <fs>.<fs> = 'Dynamisch erzeugt'.
WRITE: / <fs>.
" Für StrukturenDATA: lv_struct_name TYPE string VALUE 'SFLIGHT'.CREATE DATA lr_data TYPE (lv_struct_name).ASSIGN lr_data->* TO <fs>.10. Referenzvergleich
DATA: lv_data TYPE string VALUE 'Test'.DATA: lr_ref1 TYPE REF TO string, lr_ref2 TYPE REF TO string, lr_ref3 TYPE REF TO string.
lr_ref1 = REF #( lv_data ).lr_ref2 = REF #( lv_data ).lr_ref3 = lr_ref1.
" Referenzvergleich (zeigen auf gleiche Adresse?)IF lr_ref1 = lr_ref3. WRITE: / 'ref1 und ref3 sind identisch'. " JaENDIF.
IF lr_ref1 = lr_ref2. WRITE: / 'ref1 und ref2 sind identisch'. " Nein! (verschiedene Referenzen)ENDIF.
" WertvergleichIF lr_ref1->* = lr_ref2->*. WRITE: / 'Werte sind gleich'. " JaENDIF.Datenreferenz vs. Field-Symbol
| Aspekt | Datenreferenz | Field-Symbol |
|---|---|---|
| Typ | Variable (REF TO) | Platzhalter |
| Speichern | Ja, kann gespeichert werden | Nein, nur temporär |
| Weitergabe | Kann als Parameter übergeben werden | Nur lokal nutzbar |
| NULL-Zustand | Kann initial/ungebunden sein | Nicht zugewiesen |
| Syntax | lr_data->* | <fs> |
| Performance | Minimal langsamer | Minimal schneller |
| Anwendung | Speichern, Weitergeben | Lokaler schneller Zugriff |
" Field-Symbol: Schneller lokaler ZugriffLOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>). <fs>-field = 'X'.ENDLOOP.
" Datenreferenz: Wenn Referenz gespeichert werden mussLOOP AT lt_data REFERENCE INTO DATA(lr_line). APPEND lr_line TO lt_references. " Referenz speichernENDLOOP.Typische Anwendungsfälle
1. Optionale Parameter
METHODS: process IMPORTING ir_config TYPE REF TO ty_config OPTIONAL.
METHOD process. IF ir_config IS BOUND. " Konfiguration verwenden ELSE. " Standardwerte ENDIF.ENDMETHOD.2. Rückgabe von Referenzen
METHODS: get_instance RETURNING VALUE(rr_instance) TYPE REF TO lcl_singleton.
METHOD get_instance. IF gr_instance IS NOT BOUND. gr_instance = NEW #( ). ENDIF. rr_instance = gr_instance.ENDMETHOD.3. Dynamische Datenstrukturen
" Baum-Struktur mit ReferenzenTYPES: BEGIN OF ty_node, value TYPE string, children TYPE TABLE OF REF TO ty_node WITH EMPTY KEY, END OF ty_node.
DATA: lr_root TYPE REF TO ty_node.lr_root = NEW #( value = 'Root' ).APPEND NEW ty_node( value = 'Child 1' ) TO lr_root->children.Wichtige Hinweise / Best Practice
- Prüfen Sie immer
IS BOUNDvor der Dereferenzierung. - Verwenden Sie
REF #()stattGET REFERENCEin modernem ABAP. - Field-Symbols sind für lokalen Zugriff performanter.
- Datenreferenzen sind nötig, wenn Referenzen gespeichert oder weitergegeben werden.
CREATE DATAfür dynamische Typermittlung zur Laufzeit.- Vorsicht bei generischen Referenzen (
REF TO data) – Typsicherheit geht verloren. - Kombinieren Sie mit
LOOP AT ... REFERENCE INTOfür effizienten Tabellenzugriff. - Verwenden Sie Referenzen in
CLASS-Attributen für Objektbeziehungen.