ABAP Datenreferenzen: REF, GET REFERENCE und Dereferenzierung

kategorie
ABAP-Statements
Veröffentlicht
autor
Johannes

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 Referenz
DATA: lr_data TYPE REF TO <datentyp>.
" Generische Referenz (auf beliebige Daten)
DATA: lr_any TYPE REF TO data.
" Inline-Deklaration
DATA(lr_inline) = REF #( variable ).

Referenz erstellen

" Modern (ab 7.40): REF #()
lr_data = REF #( variable ).
" Klassisch: GET REFERENCE
GET REFERENCE OF variable INTO lr_data.
" Neues Datenobjekt erzeugen
CREATE DATA lr_data TYPE <typ>.
lr_data = NEW #( ). " Ab 7.40

Dereferenzierung

" Zugriff auf die Daten
<wert> = lr_data->*.
" Bei Strukturen: Komponentenzugriff
<wert> = lr_struct->comp_name.
" Bei Tabellen: Zugriff auf Zeilen
LOOP 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 erstellen
lr_number = REF #( lv_number ).
" Dereferenzierung: Wert lesen
WRITE: / 'Wert:', lr_number->*. " 42
" Dereferenzierung: Wert ändern
lr_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 ist
IF 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 freigeben
FREE lr_data.

3. GET REFERENCE (klassische Syntax)

DATA: lv_text TYPE string VALUE 'Hallo Welt'.
DATA: lr_text TYPE REF TO string.
" Klassische Syntax
GET REFERENCE OF lv_text INTO lr_text.
WRITE: / lr_text->*. " Hallo Welt

4. Neues Datenobjekt erzeugen

DATA: lr_number TYPE REF TO i.
" Klassisch: CREATE DATA
CREATE DATA lr_number.
lr_number->* = 42.
" Modern: NEW #()
DATA(lr_string) = NEW string( 'Neuer String' ).
WRITE: / lr_string->*.
" Mit Typ
DATA: lr_any TYPE REF TO data.
CREATE DATA lr_any TYPE i.
" Generisch mit dynamischem Typ
DATA: 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 LOOP
LOOP 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 INTO
READ 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 sammeln
APPEND REF #( lv_str1 ) TO lt_refs.
APPEND REF #( lv_str2 ) TO lt_refs.
APPEND REF #( lv_str3 ) TO lt_refs.
" Referenzen durchlaufen
LOOP AT lt_refs INTO DATA(lr_str).
WRITE: / lr_str->*.
ENDLOOP.
" Originalwerte über Referenzen ändern
READ TABLE lt_refs INTO lr_str INDEX 1.
lr_str->* = 'GEÄNDERT'.
WRITE: / lv_str1. " GEÄNDERT

7. 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.
" Verwendung
DATA: 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. " 100

8. Generische Referenzen (REF TO data)

DATA: lr_any TYPE REF TO data.
FIELD-SYMBOLS: <fs_data> TYPE any.
" Referenz auf Integer
DATA(lv_int) = 42.
lr_any = REF #( lv_int ).
" Für den Zugriff: Field-Symbol zuweisen
ASSIGN lr_any->* TO <fs_data>.
WRITE: / <fs_data>.
" Referenz auf String
DATA(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 erzeugen
CREATE DATA lr_data TYPE (lv_type).
" Wert zuweisen über Field-Symbol
FIELD-SYMBOLS: <fs> TYPE any.
ASSIGN lr_data->* TO <fs>.
<fs> = 'Dynamisch erzeugt'.
WRITE: / <fs>.
" Für Strukturen
DATA: 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'. " Ja
ENDIF.
IF lr_ref1 = lr_ref2.
WRITE: / 'ref1 und ref2 sind identisch'. " Nein! (verschiedene Referenzen)
ENDIF.
" Wertvergleich
IF lr_ref1->* = lr_ref2->*.
WRITE: / 'Werte sind gleich'. " Ja
ENDIF.

Datenreferenz vs. Field-Symbol

AspektDatenreferenzField-Symbol
TypVariable (REF TO)Platzhalter
SpeichernJa, kann gespeichert werdenNein, nur temporär
WeitergabeKann als Parameter übergeben werdenNur lokal nutzbar
NULL-ZustandKann initial/ungebunden seinNicht zugewiesen
Syntaxlr_data->*<fs>
PerformanceMinimal langsamerMinimal schneller
AnwendungSpeichern, WeitergebenLokaler schneller Zugriff
" Field-Symbol: Schneller lokaler Zugriff
LOOP AT lt_data ASSIGNING FIELD-SYMBOL(<fs>).
<fs>-field = 'X'.
ENDLOOP.
" Datenreferenz: Wenn Referenz gespeichert werden muss
LOOP AT lt_data REFERENCE INTO DATA(lr_line).
APPEND lr_line TO lt_references. " Referenz speichern
ENDLOOP.

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 Referenzen
TYPES: 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 BOUND vor der Dereferenzierung.
  • Verwenden Sie REF #() statt GET REFERENCE in modernem ABAP.
  • Field-Symbols sind für lokalen Zugriff performanter.
  • Datenreferenzen sind nötig, wenn Referenzen gespeichert oder weitergegeben werden.
  • CREATE DATA für dynamische Typermittlung zur Laufzeit.
  • Vorsicht bei generischen Referenzen (REF TO data) – Typsicherheit geht verloren.
  • Kombinieren Sie mit LOOP AT ... REFERENCE INTO für effizienten Tabellenzugriff.
  • Verwenden Sie Referenzen in CLASS-Attributen für Objektbeziehungen.