|
SAPhtml
——ABAP/4 技術總結 V3.0java
2014-10-14node
--江正軍git
C、N、D、T、I、F、P、X、string、Xstring
P:默認爲8字節,最大容許16字節。最大整數位:16*2 = 32 - 1 = 31 -14(容許最大小數位數) = 17位整數位
類型 |
最大長度(字符數) |
默認長度 |
說明 |
C |
1~262143個字符 |
1 字符 |
|
N |
1~262143個字符 |
1 字符 |
0到9之間字符組成的數字字符串 |
D |
8 個字符 |
|
日期格式必須爲 YYYYMMDD |
T |
6 個字符 |
|
格式爲 24-hour的 HHMMSS |
I |
4 bytes |
|
-2.147.483.648 to +2.147.483.647 |
F |
8 bytes |
|
小數位最大能夠到17位,便可精確到小數點後17位 |
P |
1 to 16 bytes |
8 bytes |
兩個數字位壓縮後才佔一個字節,因爲0-9的數字只須要4Bit位,因此一個字節實質上容許存儲二位數字,這就是P數據類型爲壓縮數據類型的由來。並借用半個字節來存儲小數點位置、正號、負號相關信息 |
X |
1~524,287 bytes |
1 byte |
十六進制字符 0-9, A-F具體的範圍爲:00~FF 類型X是十六進制類型,可表示內存字節實際內容,使用兩個十六制字符表示一個字節中所存儲的內容。但直接打印輸出時,輸出的仍是賦值時字面意義上的值,而不是Unicode解碼後的字符 若是未在 DATA 語句中指定參數<length>,則建立長度爲 1 注:若是值是字母,則必定要大寫 |
是一種壓縮的定點數,其數據對象佔據內存字節數和數值範圍取定義時指定的整個數據大小和小數點後位數,若是不指定小數位,則將視爲I類型。其有效數字位大小能夠是從1~31位數字(小數點與正負號佔用一個位置,半個字節),小數點後最多容許14個數字。
P類型的數據,可用於精確運算(這裏的精確指的是存儲中所存儲的數據與定義時字面上所看到的大小相同,而不存在精度丟失問題——看到的就是內存中實實在在的大小)。在使用P類型時,要先選擇程序屬性中的選項 Fixed point arithmetic(即定點算法,通常默認選中),不然系統將P類型看用整型。其效率低於I或F類型。
"16 * 2 = 32表示了整個字面意義上容許的最大字面個數,而14表示的是字面上小數點後面容許的最大小數位,而不是指14個字節,只有這裏定義時的16才表示16個字節
DATA: p(16) TYPE p DECIMALS 14 VALUE '12345678901234567.89012345678901'.
"正負符號與小數點固定要佔用半個字節,一個字面上位置,幷包括在這16個字節裏面。
"16 * 2 = 32位包括了小數點與在正負號在內
"在定義時字面上容許最長能夠達到32位,除去小數點與符號需佔半個字節之後
"有效數字位可容許31位,這31位中包括了整數位與小數位,再除去定義時小
"數位爲14位外,整數位最多還可達到17位,因此下面最多隻能是17個9
DATA: p1(16) TYPE p DECIMALS 14 VALUE '-99999999999999999'.
"P類型是以字符串來表示一個數的,與字符串不同的是,P類型中的每一個數字位只會佔用4Bit位,因此兩個數字位纔會佔用一個字節。另外,若是定義時沒有指定小數位,表示是整型,但小數點固定要佔用半個字節,因此不帶小數位與符號的最大與最小整數以下(最多容許31個9,而不是32個)
DATA: p1(16) TYPE p VALUE '+9999999999999999999999999999999'.
DATA: p2(16) TYPE p VALUE '-9999999999999999999999999999999'.
其實P類型是以字符串形式來表示一個小數,這樣才能夠做到精確,就像Java中要表示一個精確的小數要使用BigDecimal同樣,不然會丟失精度。
DATA: p(9) TYPE p DECIMALS 2 VALUE '-123456789012345.12'.
WRITE: / p."123456789012345.12-
DATA: f1 TYPE f VALUE '2.0',
f2 TYPE f VALUE '1.1',
f3 TYPE f.
f3 = f1 - f2."不能精確計算
"2.0000000000000000E+00 1.1000000000000001E+00 8.9999999999999991E-01
WRITE: / f1 , f2 , f3.
DATA: p1 TYPE p DECIMALS 1 VALUE '2.0',
p2 TYPE p DECIMALS 1 VALUE '1.1',
p3 TYPE p DECIMALS 1.
p3 = p1 - p2."能精確計算
WRITE: / p1 , p2 , p3. "2.0 1.1 0.9
Java中精確計算:
publicstaticvoid main(String[] args) {
System.out.println(2.0 - 1.1);// 0.8999999999999999
System.out.println(sub(2.0, 0.1));// 1.9
}
publicstaticdouble sub(double v1, double v2) {
BigDecimal b1 = new BigDecimal(Double.toString(v1));
BigDecimal b2 = new BigDecimal(Double.toString(v2));
return b1.subtract(b2).doubleValue();
}
透明表(還有其它數據詞典中的類型,如結構)便可看做是一種類型,也可看做是對象,因此便可使用TYPE,也能夠使用LIKE:
TYPES type6 TYPE mara-matnr.
TYPES type7 LIKE mara-matnr.
DATA obj6 TYPE mara-matnr.
DATA obj7 LIKE mara-matnr.
"SFLIGHT爲表類型
DATA plane LIKE sflight-planetype.
DATA plane2 TYPE sflight-planetype.
DATA plane3 LIKE sflight.
DATA plane4 TYPE sflight.
"syst爲結構類型
DATA sy1 TYPE syst.
DATA sy2 LIKE syst.
DATA sy3 TYPE syst-index.
DATA sy4 LIKE syst-index.
注:定義的變量名千萬別與詞典中的類型相同,不然表面上便可使用TYPE也可以使用LIKE,就會出現這兩個關鍵字(Type、Like)均可用的奇怪現像,下面是定義一個變量時與詞典中的結構同名的後果(致使)
DATA : BEGIN OF address2,
street(20) TYPE c,
city(20) TYPE c,
END OF address2.
DATA obj4 TYPE STANDARD TABLE OF address2."這裏使用的實質上是詞典中的類型address2
DATA obj5 LIKE STANDARD TABLE OF address2."這裏使用是的上面定義的變量address2
上面程序編譯經過,按理obj4定義是經過不過的(只能使用LIKE來引用另外一定義變量的類型,TYPE是不能夠的),但因爲address2是數字詞典中定義的結構類型,因此obj4使用的是數字詞典中的結構類型,而obj5使用的是LIKE,因此使用的是address2變量的類型
DESCRIBE FIELD dobj
[TYPE typ [COMPONENTS com]]
[LENGTH ilen IN {BYTE|CHARACTER} MODE]
[DECIMALS dec]
[OUTPUT-LENGTH olen]
[HELP-ID hlp]
[EDIT MASK mask].
DESCRIBE TABLE itab [KIND knd] [LINES lin] [OCCURS n].
能夠使用&或&&將多個字符模板串連接起來,能夠突破255個字符的限制,下面兩個是等效的:
|...| & |...|
|...| && |...|
若是內容只有字面常量文本(沒有變量表達式或控制字符\r \n \t),則不須要使用字符模板,可這樣(若是包含了這些控制字符時,會原樣輸出,因此有這些控制字符時,請使用 |...|將字符包起來):
`...` && `...`
可是上面3個與下面3個是不同的:
`...` & `...`
'...' & '...'
'...' && '...'
上面前兩個仍是會受255個字符長度限制,最後一個雖然不受255限制,但尾部空格會被忽略
字面常量文本(literal text)部分,使用 ||括起來,不能含有控制字符(如 \r \n \t這些控制字符),特殊字符 |{ } \須要使用 \進行轉義:
txt = |Characters \|, \{, and \} have to be escaped by \\ in literal text.|.
字符串表達式:
str = |{ ( 1 + 1 ) * 2 }|."算術計算表達式
str = |{ |aa| && 'bb' }|."字符串表達式
str = |{ str }|."變量名
str = |{ strlen( str ) }|."內置函數
數據元素是構成結構、表的基本組件,域又定義了數據元素的技術屬性。Data element主要附帶Search Help、Parameter ID、以及標籤描述,而類型是由Domain域來決定的。Domain主要從技術方面描述了Data element,如Data Type數據類型、Output Length輸出長度、Convers. Routine轉換規則、以及Value Range取值範圍
將技術信息從Data element提取出來爲Domain域的好處:技術信息造成的Domain能夠共用,而每一個表字段的業務含意不同,會致使其描述標籤、搜索幫助不同,因此牽涉到業務部分的信息直接Data element中進行描述,而與業務無關的技術信息部分則分離出來造成Domain
當你在ABAP程序中引用了ABAPDictionary,則預置Dictionary類型則會轉換爲相應的ABAP類型,預置的Dictionary類型轉換規則表以下:
Dictionarytype |
Meaning |
Maximumlengthn |
ABAPtype |
DEC |
Calculation/amountfield |
1-31, 1-17intables |
P((n+1)/2) |
INT1 |
Single-byte integer |
3 |
Internalonly |
INT2 |
Two-byteinteger |
5 |
Internalonly |
INT4 |
Four-byteinteger |
10 |
I |
CURR |
Currencyfield貨幣字段 |
1-17 |
P((n+1)/2) |
CUKY |
Currencykey貨幣代碼 |
5 |
C(5) |
QUAN |
Amount金額 |
1-17 |
P((n+1)/2) |
UNIT |
Unit單位 |
2-3 |
C(n) |
PREC |
Accuracy |
2 |
X(2) |
FLTP |
Floating pointnumber |
16 |
F(8) |
NUMC |
Numeric text數字字符 |
1-255 |
N(n) |
CHAR |
Character字符 |
1-255 |
C(n) |
LCHR |
Long character |
256-max |
C(n) |
STRING |
Stringofvariable length |
1-max |
STRING. |
RAWSTRING |
Byte sequence of variable length |
1-max |
XSTRING |
DATS |
Date |
8 |
D |
ACCP |
Accounting period YYYYMM |
6 |
N(6) |
TIMS |
Time HHMMSS |
6 |
T |
RAW |
Byte sequence |
1-255 |
X(n) |
LRAW |
Long byte sequence |
256-max |
X(n) |
CLNT |
Client |
3 |
C(3) |
LANG |
Language |
internal 1, external 2 |
C(1) |
這裏的「容許最大長度m」表示的是字面上容許的字符位數,而不是指底層所佔內存字節數,如
int1的取值爲0~255,因此是3位(不包括符號位)
int2的取值爲-32768~32767,因此是5位
lLCHR and LRAW類型容許的最大值爲INT2 最大值
lRAWSTRING and STRING 具備可變長度,最大值能夠指定,但沒有上限
lSSTRING 長度是可變的,其最大值必須指定且上限爲255。與CHAR類型相比其優點是它與ABAP type string進行映射。
這些預置的Dictionary類型在建立Data element、Domain時能夠引用
在Unicode系統中,一個字符佔兩個字節
SPLIT dobj AT sep INTO { {result1 result2 ...} | {TABLE result_tab} }必須指定足夠目標字段。不然,用字段dobj的剩餘部分填充最後目標字段幷包含分界符;或者使用內表動態接收
SHIFT dobj {[{BY num PLACES}|{UP TO sub_string}][[LEFT|RIGHT][CIRCULAR]]}
| { {LEFT DELETING LEADING}|{RIGHT DELETING TRAILING} } pattern
對於固定長度字符串類型,shift產生的空位會使用空格或十六進制的0(若是爲X類型串時)來填充
向右移動時前面會補空格,固定長度類型字符串與String結果是不同:String類型右移後不會被截斷,只是字串前面補相應數量的空格,但若是是C類型時,則會截斷;左移後後面是否被空格要看是不是固定長度類型的字符串仍是變長的String類型串,左移後C類型會補空格,String類型串不會(會縮短)
CIRCULAR:將移出的字符串放在左邊或者左邊
pattern:只要前導或尾部字符在指定的pattern字符集裏就會被去掉,直到第一個不在模式pattern的字符止
CONDENSE <c> [NO-GAPS].若是是C類型只去掉前面的空格(由於是定長,即便後面空格去掉了,左對齊時後面會補上空格),若是是String類型,則後面空格也會被去掉;字符串中間的多個連續的空格使用一個空格替換(String類型也是這樣);NO-GAPS:字符串中間的全部空格都也都會去除(String類型也是這樣);空格去掉後會左對齊
CONCATENATE {dobj1 dobj2 ...}|{LINES OF itab}
INTO result
[SEPARATED BY sep]
[RESPECTING BLANKS].
CDNT類型的前導空格會保留,尾部空格都會被去掉,但對String類型全部空格都會保留;對於c, d, n, t類型的字符串有一個RESPECTING BLANKS選項可以使用,表示尾部空格也會保留。注:使用 `` 對String類型進行賦值時纔會保留尾部空格 字符串鏈接能夠使用 && 來操做,具體請參考這裏
strlen(arg)、Xstrlen(arg)String類型的尾部空格會計入字符個數中,但C類型的變量尾部空格不會計算入
substring( val = TEXT [off = off] [len = len] )
count( val = TEXT {sub = substring}|{regex = regex} )匹配指定字符串substring或正則式regex出現的子串次數,返回的類型爲i整型類型
contains( val = TEXT REGEX = REGEX)是否包含。返回布爾值,注:只能用在if、While等條件表達式中
matches( val = TEXT REGEX = REGEX)regex表達式要與text徹底匹配,這與contains是不同的。返回布爾值,也只能用在if、While等條件表達式中
match( val = TEXT REGEX = REGEX occ = occ)返回的爲匹配到的字符串。注:每次只匹配一個。occ:表示需匹配到第幾回出現的子串。若是爲正,則從頭日後開始計算,若是爲負,則從尾部向前計算
find( val = TEXT {sub = substring}|{regex = regex}[occ = occ] )查找substring或者匹配regex的子串的位置。若是未找到,則返回 -1,返回的爲offset,因此從0開始
FIND ALL OCCURRENCES OF REGEX regex IN dobj
[MATCH COUNT mcnt] 成功匹配的次數
{ {[MATCH OFFSET moff][MATCH LENGTH mlen]}最後一次總體匹配到的串(總體串,最外層分組,而不是指正則式最內最後一個分組)起始位置與長度
| [RESULTS result_tab|result_wa] } result_tab接收全部匹配結果,result_wa只能接收最後一次匹配結果
[SUBMATCHES s1 s2 ...].一般與前面的MATCH OFFSET/ LENGTH一塊兒使用。只會接收使用括號進行分組的子組。若是變量s1 s2 ...比分組的數量多,則多餘的變量被initial;若是變量s1 s2 ...比分組的數量少,則多餘的分組將被忽略;且只存儲第一次或最後一次匹配到的結果
replace( val = TEXT REGEX = REGEX WITH = NEW)使用new替換指定的子符串,返回String類型
REPLACE ALL OCCURRENCES OF REGEX regex IN dobj WITH new
DATA: text TYPE string VALUE `Cathy's cat with the hat sat on Matt's mat.`,
regx TYPE string VALUE `\<.at\>`."\< 單詞開頭,\> 單詞結尾
DATA: counts TYPE i,
index TYPE i,
substr TYPE string.
WRITE / text.
NEW-LINE.
counts = count( val = text regex = regx )."返回匹配次數
DO counts TIMES.
index = find( val = text regex = regx occ = sy-index )."返回匹配到的的起始位置索引
substr = match( val = text regex = regx occ = sy-index )."返回匹配到的串
index = index + 1.
WRITE AT index substr.
ENDDO.
DATA: moff TYPE i,
mlen TYPE i,
s1 TYPE string,
s2 TYPE string,
s3 TYPE string,
s4 TYPE string.
FIND ALL OCCURRENCES OF REGEX `((\w+)\W+\2\W+(\w+)\W+\3)`"\2 \3 表示反向引用前面匹配到的第二與第三個子串
IN `Hey hey, my my, Rock and roll can never die Hey hey, my my`"會匹配二次,但只會返回第二次匹配到的結果,第一次匹配到的子串不會存儲到s1、s2、s3中去
IGNORING CASE
MATCH OFFSET moff
MATCH LENGTH mlen
SUBMATCHES s1 s2 s3 s4."根據從外到內,從左到右的括號順序依次存儲到s1 s2…中,注:只取出使用括號括起來的子串,如想取總體子串則也要括起來,這與Java不一樣
WRITE: / s1, / s2,/ s3 ,/ s4,/ moff ,/ mlen."s4會被忽略
DATA: result TYPE STANDARD TABLE OF string WITH HEADER LINE .
"與Java不一樣,只要是括號括起來的都稱爲子匹配(即便用總體也用括號括起來了),
"無論括號嵌套多少層,統稱爲子匹配,且匹配到的全部子串都會存儲到,
"MATCH_RESULT-SUBMATCHES中,即便最外層的括號匹配到的子串也會存儲到SUBMATCHES
"內表中。括號解析的順序爲:從外到內,從左到右的優先級順序來解析匹配結構。
"Java中的group(0)存儲的是總體匹配串,即便總體未(或使用)使用括號括起來
PERFORM get_match TABLES result
USING '2011092131221032' '(((\d{2})(\d{2}))(\d{2})(\d{2}))'.
LOOP AT result .
WRITE: / result.
ENDLOOP.
FORM get_match TABLES p_result"返回全部分組匹配(括號括起來的表達式)
USING p_str
p_reg.
DATA: result_tab TYPE match_result_tab WITH HEADER LINE.
DATA: subresult_tab TYPE submatch_result_tab WITH HEADER LINE.
"注意:帶表頭時 result_tab 後面必定要帶上中括號,不然激活時出現奇怪的問題
FIND ALL OCCURRENCES OF REGEX p_reg IN p_str RESULTS result_tab[].
"result_tab中存儲了匹配到的子串自己(與Regex總體匹配的串,存儲在
"result_tab-offset、result_tab-length中)以及所子分組(括號部分,存儲在
"result_tab-submatches中)
LOOP AT result_tab .
"如需取總體匹配到的子串(與Regex總體匹配的串),則使用括號將總體Regex括起來
"來便可,括起來後也會自動存儲到result_tab-submatches,而不須要在這裏像這樣讀取
* p_result = p_str+result_tab-offset(result_tab-length).
* APPEND p_result.
subresult_tab[] = result_tab-submatches.
LOOP AT subresult_tab.
p_result = p_str+subresult_tab-offset(subresult_tab-length).
APPEND p_result.
ENDLOOP.
ENDLOOP.
ENDFORM.
regex = Regular expression [ˈreɡjulə]
cl_abap_regex:與Java中的 java.util.regex.Pattern的類對應
cl_abap_matcher:與Java中的 java.util.regex.Matcher的類對應
是否徹底匹配(正則式中沒必要使用 ^ 與 $);matches爲靜態方法,而match爲實例方法,做用都是同樣
DATA: matcher TYPE REF TO cl_abap_matcher,
match TYPE match_result,
match_line TYPE submatch_result.
"^$能夠省略,由於matches方法自己就是徹底匹配整個Regex
IF cl_abap_matcher=>matches( pattern = '^(db(ai).*)$' text = 'dbaiabd' ) = 'X'.
matcher = cl_abap_matcher=>get_object( )."獲取最後一次匹配到的 Matcher 實例
match = matcher->get_match( ). "獲取最近一次匹配的結果(注:是總體匹配的結果)
WRITE / matcher->text+match-offset(match-length).
LOOP AT match-submatches INTO match_line. "提取子分組(括號括起來的部分)
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.
DATA: matcher TYPE REF TO cl_abap_matcher,
match TYPE match_result,
match_line TYPE submatch_result.
"^$能夠省略,由於matche方法自己就是徹底匹配整個Regex
matcher = cl_abap_matcher=>create( pattern = '^(db(ai).*)$' text = 'dbaiabd' ).
IF matcher->match( ) = 'X'.
match = matcher->get_match( ). "獲取最近一次匹配的結果
WRITE / matcher->text+match-offset(match-length).
LOOP AT match-submatches INTO match_line. "提取子分組(括號括起來的部分)
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.
是否包含(也可在正則式中使用 ^ 與 $ 用於徹底匹配檢查,或者使用 ^ 檢查是否匹配開頭,或者使用 $ 匹配結尾)
DATA: matcher TYPE REF TO cl_abap_matcher,
match TYPE match_result,
match_line TYPE submatch_result.
IF cl_abap_matcher=>contains( pattern = '(db(ai).{2}b)' text = 'dbaiabddbaiabb' ) = 'X'.
matcher = cl_abap_matcher=>get_object( ). "獲取最後一次匹配到的 Matcher 實例
match = matcher->get_match( ). "獲取最近一次匹配的結果
WRITE / matcher->text+match-offset(match-length).
LOOP AT match-submatches INTO match_line. "提取子分組(括號括起來的部分)
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDIF.
DATA: matcher TYPE REF TO cl_abap_matcher,
match_line TYPE submatch_result,
itab TYPE match_result_tab WITH HEADER LINE.
matcher = cl_abap_matcher=>create( pattern = '<[^<>]*(ml)>' text = '<html>hello</html>' )."建立 matcher 實例
"注:子分組存儲在itab-submatches字段裏
itab[] = matcher->find_all( ).
LOOP AT itab .
WRITE: / matcher->text, itab-offset, itab-length,matcher->text+itab-offset(itab-length).
LOOP AT itab-submatches INTO match_line. "提取子分組(括號括起來的部分)
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDLOOP.
逐個找出匹配的子串,包括子分組(括號括起的部分)
DATA: matcher TYPE REF TO cl_abap_matcher,
match TYPE match_result, match_line TYPE submatch_result,
itab TYPE match_result_tab WITH HEADER LINE.
matcher = cl_abap_matcher=>create( pattern = '<[^<>]*(ml)>' text = '<html>hello</html>' ).
WHILE matcher->find_next( ) = 'X'.
match = matcher->get_match( )."獲取最近一次匹配的結果
WRITE: / matcher->text, match-offset, match-length,matcher->text+match-offset(match-length).
LOOP AT match-submatches INTO match_line. "提取子分組(括號括起來的部分)
WRITE: /20 match_line-offset, match_line-length,matcher->text+match_line-offset(match_line-length).
ENDLOOP.
ENDWHILE.
DATA: matcher TYPE REF TO cl_abap_matcher,
length TYPE i,offset TYPE i,
submatch TYPE string.
matcher = cl_abap_matcher=>create( pattern = '(<[^<>]*(ml)>)' text = '<html>hello</html>' ).
WHILE matcher->find_next( ) = 'X'. "循環2次
"爲0時,表示取整個Regex匹配到的子串,這與Java同樣,但若是整個Regex使用括號括起來後,
"則分組索引爲1,這又與Java不同(Java無論是否使用括號將整個Regex括起來,分組索引號都爲0)
"上面Regex中共有兩個子分組,再加上整個Regex爲隱含分組,因此一共爲3組
DO 3 TIMES.
"在當前匹配到的串(整個Regex相匹配的串)中返回指定子分組的匹配到的字符串長度
length = matcher->get_length( sy-index - 1 ).
"在當前匹配到的串(整個Regex相匹配的串)中返回指定子分組的匹配到的字符串起始位置
offset = matcher->get_offset( sy-index - 1 ).
"在當前匹配到的串(整個Regex相匹配的串)中返回指定子分組的匹配到的字符串
submatch = matcher->get_submatch( sy-index - 1 ).
WRITE:/ length , offset,matcher->text+offset(length),submatch.
ENDDO.
SKIP.
ENDWHILE.
DATA: matcher TYPE REF TO cl_abap_matcher,
count TYPE i,
repstr TYPE string.
matcher = cl_abap_matcher=>create( pattern = '<[^<>]*>' text = '<html>hello</html>' ).
count = matcher->replace_all( ``)."返回替換的次數
repstr = matcher->text. "獲取被替換後的新串
WRITE: / count , repstr.
內表:若是使用有表頭行的內表,CLEAR 僅清除表格工做區域。要重置整個內表而不清除表格工做區域,使用REFRESH語句或 CLEAR 語句CLEAR <itab>[].;REFRESH加不加中括號都是隻清內表,另外REFRESH是專爲清內表的,不能清基本類型變量,但CLEAR能夠
以上都不會釋放掉內表所佔用的空間,若是想初始化內表的同時還要釋放所佔用的空間,請使用:FREE <itab>.
報表程序中選擇屏幕事件塊(AT SELECTION-SCREEN)與邏輯數據庫事件塊、以及methods(類中的方法)、subroutines(FORM子過程)、function modules(Function函數)中聲明的變量爲局部的,即在這些塊裏聲明的變量不能在其餘塊裏使用,但這些局部變量能夠覆蓋同名的全局變量;除這些處理塊外,其餘塊裏聲明的變量都屬於全局的(如報表事件塊、列表事件塊、對話Module),效果與在程序最開頭定義的變量效果是同樣的,因此能夠在其餘處理塊直接使用(但要注意的是,需遵照先定義後使用的原則,這種前後關係是從語句書寫順序來講的,與事件塊的自己運行順序沒有關係);另外,局部變量聲明時,無論在處理塊的任何地方,其效果都是至關於處理塊裏的全局變量,而不像其餘語言如Java那樣:局部變量的做用域能夠存在於任何花括號{}之間(這就意味着局部變量在處理過程範圍內是全局的),以下面的i,在ABAP語言中仍是會累加輸出,而不會永遠是1(在Java語言中會是1):
FORM aa.
DO 10 TIMES.
DATA: i TYPE i VALUE 0.
i = i + 1.
WRITE: / i.
ENDDO.
ENDFORM.
Form、Function中的TABLES參數,TYPE與LIKE後面只能接標準內表類型或標準內表對象,若是要使用排序內表或者哈希內表,則只能使用USING(Form)與CHANGING方式來代替。當把一個帶表頭的實參經過TABLES參數傳遞時,表頭也會傳遞過去,若是實參不帶表頭或者只傳遞了表體(使用了[]時),系統會自動爲內表參數變量建立一個局部空的表頭
無論是以TABLES仍是以USING(Form)非值、CHANGE非值方式傳遞時,都是以引用方式(即別名,不是指地址,注意與Java中的傳引用區別:Java實爲傳值,但傳遞的值爲地址的值,而ABAP中傳遞的是否爲地址,則要看實參是不是經過Type ref to定義的)傳遞;但若是USING值傳遞,則對形參數的修改不會改變實參,由於此時不是引用傳遞;但若是CHANGE值傳遞,對形參數的修改仍是會改變實參,只是修改的時機在Form執行或Function執行完後,纔去修改
Form中經過引用傳遞時,USING與CHANGING徹底同樣;但CHANGING爲值傳遞方式時,須要在Form執行完後,纔去真正修改實參變量的內容,因此CHANGING傳值與傳引用其結果都是同樣:結果都修改了實參內容,只是修改的時機不太同樣而已
FORM subr [TABLES t1 [{TYPE itab_type}|{LIKE itab}|{STRUCTURE struc}]
t2 […]]
[USING { VALUE(p1)|p1 } [ { TYPE generic_type }
| { LIKE <generic_fs>|generic_para }
| { TYPE {[LINE OF] complete_type}|{REF TO type} }
| { LIKE {[LINE OF] dobj} | {REF TO dobj} }
| STRUCTURE struc]
{ VALUE(p2)|p2 } […]]
[CHANGING{ VALUE(p1)|p1 } [ { TYPE generic_type }
| { LIKE <generic_fs>|generic_para }
| { TYPE {[LINE OF] complete_type} | {REF TO type} }
| { LIKE {[LINE OF] dobj} | {REF TO dobj} }
| STRUCTURE struc]
{ VALUE(p2)|p2 } […]]
[RAISING {exc1|RESUMABLE(exc1)} {exc2|RESUMABLE(exc2)} ...].
generic_type:爲通用類型
complete_type:爲徹底限制類型
<generic_fs>:爲字段符號變量類型,以下面的 fs 形式參數
generic_para:爲另外一個形式參數類型,以下面的 b 形式參數
DATA: d(10) VALUE'11'.
FIELD-SYMBOLS: <fs> LIKE d.
ASSIGN d TO <fs>.
PERFORM aa USING <fs> d d.
FORM aa USING fs like <fs> a like d b like a.
WRITE:fs,/ a , / b.
ENDFORM.
若是沒有給形式參數指定類,則爲ANY類型
若是TABLES與USING、CHANGING一塊兒使用時,則必定要按照TABLES、USING、CHANGING順序聲明
值傳遞中的VALUE關鍵字只是在FORM定義時出現,在調用時PERFORM語句中無需出現,也就是說,調用時值傳遞和引用傳遞不存在語法格式差異
DATA : i TYPE i VALUE 100.
WRITE: / 'frm_ref===='.
PERFORM frm_ref USING i .
WRITE: / i."200
WRITE: / 'frm_val===='.
i = 100.
PERFORM frm_val USING i .
WRITE: / i."100
WRITE: / 'frm_ref2===='.
"不能將下面的變量定義到frm_ref2過程當中,若是這樣,下面的dref指針在調用frm_ref2 後,指向的是Form中局部變量內存,爲不安全發佈,運行會拋異常,由於From結束後,它所擁有的全部變量內存空間會釋放掉
DATA: i_frm_ref2 TYPE i VALUE 400.
i = 100.
DATA: dref TYPE REF TO i .
get REFERENCE OF i INTO dref.
PERFORM frm_ref2 USING dref ."傳遞的內容爲地址,屬於別名引用傳遞
WRITE: / i."4000
field-SYMBOLS : <fs> TYPE i .
ASSIGN dref->* to <fs>."因爲frm_ref2過程當中已修改了dref的指向,現指向了i_frm_ref2 變量的內存空間
WRITE: / <fs>."400
WRITE: / 'frm_val2===='.
i = 100.
DATA: dref2 TYPE REF TO i .
get REFERENCE OF i INTO dref2.
PERFORM frm_val2 USING dref2 .
WRITE: / i."4000
ASSIGN dref2->* to <fs>.
WRITE: / <fs>."4000
FORM frm_ref USING p_i TYPE i ."C++中的引用參數傳遞:p_i爲實參i的別名
WRITE: / p_i."100
p_i = 200."p_i爲參數i的別名,因此能夠直接修改實參
ENDFORM.
FORM frm_val USING value(p_i)."傳值:p_i爲實參i的拷貝
WRITE: / p_i."100
p_i = 300."因爲是傳值,因此不會修改主調程序中的實參的值
ENDFORM.
FORM frm_ref2 USING p_i TYPE REF TO i ."p_i爲實參dref的別名,相似C++中的引用參數傳遞(傳遞的內容爲地址,而且屬於別名引用傳遞)
field-SYMBOLS : <fs> TYPE i .
"如今<fs>就是實參所指向的內存內容的別名,表明實參所指向的實際內容
ASSIGN p_i->* to <fs>.
WRITE: / <fs>."100
<fs> = 4000."直接修改實參所指向的實際內存
DATA: dref TYPE REF TO i .
get REFERENCE OF i_frm_ref2 INTO dref.
"因爲USING爲C++的引用參數,因此這裏修改的直接是實參所存儲的地址內容,這裏的p_i爲傳進來的dref的別名,是同一個變量,因此實參的指向也發生了改變(這與Java中傳遞引用是不同的,Java中傳遞引用時爲地址的拷貝,即Java中永遠也只有傳值,但C/C++/ABAP中能夠傳遞真正引用——別名)
p_i = dref."此處會修改實參的指向
ENDFORM.
FORM frm_val2 USING VALUE(p_i) TYPE REF TO i ."p_i爲實參dref2的拷貝,相似Java中的引用傳遞(雖然傳遞的內容爲地址,但傳遞的方式屬於地址拷貝——值傳遞)
field-SYMBOLS : <fs> TYPE i .
"如今<fs>就是實參所指向的內存內容的別名,表明實參所指向的實際內容
ASSIGN p_i->* to <fs>.
WRITE: / <fs>."100
<fs> = 4000."但這裏仍是能夠直接修改實參所指向的實際內容
DATA: dref TYPE REF TO i .
get REFERENCE OF i_frm_ref2 INTO dref.
"這裏與過程 frm_ref2 不同,該過程 frm_val2 參數的傳遞方式與java中的引用傳遞是原理是同樣的:傳遞的是地址拷貝,因此下面不會修改主調程序中實參dref2的指向,它所改變的只是拷貝過來的Form中局部形式參數的指向
p_i = dref.
ENDFORM.
當使用Function Builder建立函數組時,系統會自動建立main program與相應的include程序:
l<fgrp>爲Function Group的名稱
lSAPL<fgrp>爲主程序名,它將Function Group裏的全部Include文件包括進來,除了INCLUDE語句以外,沒有其餘語句了
lL<fgrp>TOP,裏面有FUNCTION-POOL語句,以及全部Function Module均可以使用的全局數據定義
lL<fgrp>UXX,也只有INCLUDE語句,它所包括的Include文件爲相應具體Function Module所對應Include文件名:L<fgrp>U01、L<fgrp>U02、...這些Include文件實際上包含了所對應的Function Module代碼(即雙擊它們進去就是對應的Function,而顯示的不是真正Include文件所對應的代碼)
lL<fgrp>U01和L<fgrp>U02中的01、02編號對應L<fgrp>UXX中的「XX」,表明其建立前後的序號,例如L<fgrp>U01和L<fgrp>U02是頭兩個被建立的函數,在函數組中建立出的函數代碼就放在相應的L<fgrp>UXX(這裏的XX表明某個數字,而不是字面上的XX)Include頭文件中
lL<fgrg>FXX,用來存一些Form子過程,而且能夠被全部的Function Modules所使用(不是針對某個Function Module的,但通常在設計時會針對每一個Function Module設計這樣單獨的Include文件,這是一個好習慣),而且在使用時不須要在Function Module中使用INCLUDE語句包含它們(由於這些文件在主程序SAPL<fgrp>裏就已經被Include進來了)。另外,L<fgrg>FXX中的F是指Form的意思,這是一種名稱約束而已,在建立時咱們能夠隨便指定,通常還有IXX(表示些類Include文件包括的是一些PAI事件中調用的Module,有時乾脆直接使用L<fgrg>PAI或者L<fgrg>PAIXX),OXX(表示些類Include文件包括的是一些PBO事件中調用的Module,有時乾脆直接使用L<fgrg>PBO或者L<fgrg>PBOXX)。注:若是Form只被某一函數單獨使用,實質上還可直接將這些Form定義在Function Module裏的ENDFUNCTION語句後面
當你調用一個function module時,系統加將整個function group(包括Function Module、Include文件等)加載到主調程序所在的internal session中,而後該Function Module獲得執行,該Function Group一直保留在內存中,直到internal session結束。Function Group中的所定義的Include文件中的變量是全局,被全部Function Module共享,因此Function Group比如Java中的類,而Function Module則比如類中的方法,因此Function Group中的Include文件中定義的東西是全局型的,能被全部Function Module所共享使用
function fuc_ref .
*"-------------------------------------------------------------------
*"*"Local Interface:
*" IMPORTING
*" REFERENCE(I_I1) TYPE IREFERENCE(別名)爲參數的默認傳遞類型
*" VALUE(I_I2) TYPE I 定義時勾選了Pass Value選項纔會是 VALUE類型
*" REFERENCE(I_I3) TYPE REF TO I
*" VALUE(I_I4) TYPE REF TO I
*" EXPORTING
*" REFERENCE(E_I1) TYPE I
*" VALUE(E_I2) TYPE I
*" REFERENCE(E_I3) TYPE REF TO I
*" VALUE(E_I4) TYPE REF TO I
*" TABLES
*" T_1 TYPE ZJZJ_ITAB
*" CHANGING
*" REFERENCE(C_I1) TYPE I
*" VALUE(C_I2) TYPE I
*" REFERENCE(C_I3) TYPE REF TO I
*" VALUE(C_I4) TYPE REF TO I
*"-------------------------------------------------------------------
write: / i_i1."1
"因爲i_i1爲輸入類型參數,且又是引用類型,實參不能被修改。這裏i_i1是以C++中的引用(別名)參數方式傳遞參數,因此若是修改了i_i1就會修改實際參數,因此函數中不能修改REFERENCE 的 IMPORTING類型的參數,若是去掉下面註釋則編譯出錯
"i_i1 = 10.
write: / i_i2."2
"雖然i_i2是輸入類型的參數,但不是引用類型,因此能夠修改,編譯能經過但不會修改外面實參的值,只是修改了該函數局部變量的值
i_i2 = 20.
field-symbols: <fs> type i .
assign i_i3->* to <fs>.
"因爲i_i3存儲的是地址,因此先要解引用再能使用
write: / <fs>.
"同上面,REFERENCE的IMPORTING類型的參數不能被修改:這裏即不能修改實參的指向"GET REFERENCE OF 30 INTO i_i3."雖然不能夠修改實參的指向,但能夠修改實參所指向的實際內容
<fs> = 30.
assign i_i4->* to <fs>.
"i_i4存儲也的是地址,因此先要解引用再能使用
write: / <fs>.
"雖然i_i4是輸入類型的參數,但不是引用類型,因此能夠修改,只會修改函數中的局部參數i_i4的指向,但並不會修改實參的指向
get reference of 40 into i_i4.
"雖然不能修改實參的指向,但能夠直接修改實參的所指向的實際內容
<fs> = 400.
WRITE: / c_i1."111
"c_i1爲實參的別名,修改形參就等於修改實參內容
c_i1 = 1110.
WRITE: / c_i2."222
"c_i2爲實參的副本,因此不會影響實參的內容,可是,因爲是CHANGING類型的參數,且爲值傳遞,在函數正常執行完後,仍是會將該副本再次拷貝給實參,因此最終實參仍是會被修改
c_i2 = 2220.
ENDFUNCTION.
調用程序:
DATA: i_i1 TYPE i VALUE 1,
i_i2 TYPE i VALUE 2,
i_i3 TYPE REF TO i ,
i_i4 TYPE REF TO i ,
c_i1 TYPE i VALUE 111,
c_i2 TYPE i VALUE 222,
c_i3 TYPE REF TO i ,
c_i4 TYPE REF TO i ,
t_1 TYPE zjzj_itab WITH HEADER LINE.
DATA: i_i3_ TYPE i VALUE 3.
GET REFERENCE OF i_i3_ INTO i_i3.
DATA: i_i4_ TYPE i VALUE 4.
GET REFERENCE OF i_i4_ INTO i_i4.
DATA: c_i3_ TYPE i VALUE 333.
GET REFERENCE OF c_i3_ INTO c_i3.
DATA: c_i4_ TYPE i VALUE 444.
GET REFERENCE OF c_i4_ INTO c_i4.
CALL FUNCTION 'FUC_REF'
EXPORTING
i_i1 = i_i1
i_i2 = i_i2
i_i3 = i_i3
i_i4 = i_i4
TABLES
t_1 = t_1
CHANGING
c_i1 = c_i1
c_i2 = c_i2
c_i3 = c_i3
c_i4 = c_i4.
WRITE: / i_i2."2
WRITE: / i_i3_."30
WRITE: / i_i4_."400
WRITE: / c_i1."1110
WRITE: / c_i2."2220
字段符號能夠看做僅是已經被解引用的指針(相似於C語言中帶有解引用操做符 * 的指針),但更像是C++中的引用類型(int i ;&ii= i;),即某個變量的別名,它與真正的指針仍是有很大的區別的,在ABAP中引用變量(經過TYPE REF TO定義的變量)才比如C語言中的指針
ASSIGN ... TO <fs>:將某個內存區域分配給字段符號,這樣字段符號就表明了該內存區域,即該內存區域別名
TYPES: BEGIN OF t_date,
year(4) TYPE n,
month(2) TYPE n,
day(2) TYPE n,
END OF t_date.
FIELD-SYMBOLS <fs> TYPE t_date."將<fs>定義成了具體限定類型
ASSIGN sy-datum TO <fs> CASTING. "後面沒有指定具體類型,因此使用定義時的類型進行隱式轉換
DATA txt(8) TYPE c VALUE '19980606'.
FIELD-SYMBOLS <fs>.
ASSIGN txt TO <fs> CASTING TYPE d."因爲定義時未指定具體的類型,因此這裏須要顯示強轉
UNASSIGN:該語句是初始化<FS>字段符號,執行後字段符號將再也不引用內存區域,<fs> is assigned返回假
CLEAR:與UNASSIGN不一樣的是,只有一個做用就是初始化它所指向的內存區域,而不是解除分配
TYPE REF TO data 數據引用data references
TYPE REF TO object 對象引用object references
除了object,全部的通用類型都能直接用TYPE後面(如TYPE data,但沒有TYPE object,object不能直接跟在TYPE後面,只能跟在TYPE REF TO後面)
TYPE REF TO 後面可接的通用類型只能是data(數據引用)或者是object(對象引用)通用類型,其餘通用類型不行
DATA: dref TYPE REF TO i ."dref即爲數據引用,即數據指針,指向某個變量或常量,存儲變量地址
CREATE DATA dref.
dref->* = 2147483647."可直接解引用使用,不須要先經過分配給字段符號後再使用
DATA: BEGIN OF strct,
c,
END OF strct.
DATA: dref LIKE REF TO strct .
CREATE DATA dref .
dref->*-c = 'A'.
TYPES: tpy TYPE c.
DATA: c1 TYPE REF TO tpy.
DATA: c2 LIKE REF TO c1."二級指針
GET REFERENCE OF 'a' INTO c1.
GET REFERENCE OF c1 INTO c2.
WRITE: c2->*->*."a
CLASS cl DEFINITION.
PUBLIC SECTION.
DATA: i VALUE 1.
ENDCLASS.
CLASS cl IMPLEMENTATION.
ENDCLASS.
DATA: obj TYPE REF TO cl.
CREATE OBJECT obj. "建立對象
DATA: oref LIKE REF TO obj. "oref即爲對象引用,即對象指針,指向某個對象,存儲對象地址
GET REFERENCE OF obj INTO oref. "獲取對象地址
WRITE: oref->*->i."1
DATA: e_i3 TYPE REF TO i .
GET REFERENCE OF 33 INTO e_i3.
WRITE: e_i3->*."33
"但不能修改常量的值
"e_i3->* = 44.
DATA: i TYPE i VALUE 33,
dref LIKE REF TO i."存儲普通變量的地址
GET REFERENCE OF i INTO dref.
dref->* = 44.
WRITE: i. "44
SORT itab BY (comp1)...(compn)
READ TABLE itab WITH KEY(k1)=v1...(kn)=vn
READ TABLE itab...INTOwaCOMPARING(comp1)...(compn) TRANSPORTING(comp1)...
MODIFY [TABLE] itab TRANSPORTING(comp1)...(compn)
DELETE TABLEitabWITH TABLE KEY(comp1)...(compn)
DELETE ADJACENT DUPLICATES FROM itab COMPARING(comp1)...(compn)
AT NEW/END OF (comp)
CREATE DATA ... TYPE (type)...
DATA: a TYPE REF TO i.
CREATE DATA a TYPE ('I').
a->* = 1.
CREATE OBJECT ... TYPE (type)...請參考類對象反射章節
MODIFY/UPDATE(dbtab)...
CALL METHOD (meth_name)
| cref->(meth_name)
| iref->(meth_name)
| (class_name)=>(meth_name)
| class=>(meth_name)
| (class_name)=>meth
實例請參考類對象反射章節
FIELD-SYMBOLS:<fs>.
DATA:str(20) TYPE c VALUE 'Output String',
name(20) TYPE c VALUE 'STR'.
"靜態分配:編譯時就知道要分配的對象名
ASSIGN name TO <fs>."結果是<fs>與name變量等同
"經過變量名動態訪問變量
ASSIGN (name) TO <fs>."結果是是<fs>的值爲str變量值
DATA: BEGIN OF line,
col1 TYPE i VALUE '11',
col2 TYPE i VALUE '22',
col3 TYPE i VALUE '33',
END OF line.
DATA comp(5) VALUE 'COL3'.
FIELD-SYMBOLS: <f1>, <f2>, <f3>.
ASSIGN line TO <f1>.
ASSIGN comp TO <f2>.
"還可以直接使用如下的語法訪問其餘程序中的變量
ASSIGN ('(ZJDEMO)SBOOK-FLDATE') TO <fs>.
"經過索引動態的訪問結構成員
ASSIGN COMPONENT sy-index OF STRUCTURE <f1> TO <f3>.
"經過字段名動態的訪問結構成員
ASSIGN COMPONENT <f2>OF STRUCTURE <f1> TO <f3>.
"若是定義的內表沒有組件名時,能夠使用索引爲0的組件來訪問這個無名字段(注:不是1)
ASSIGN COMPONENT 0 OF STRUCTURE itab TO <fs>.
ASSIGN oref->('attr') TO <attr>.
ASSIGN oref->('static_attr') TO <attr>.
ASSIGN ('C1')=>('static_attr') TO <attr>.
ASSIGN c1=>('static_attr') TO <attr>.
ASSIGN ('C1')=>static_attr TO <attr>.
實例請參考類對象反射章節
|--CL_ABAP_DATADESCR
| |--CL_ABAP_REFDESCR
| |--CL_ABAP_COMPLEXDESCR
|--CL_ABAP_INTFDESCR
DATA: structtype TYPE REF TO cl_abap_structdescr.
structtype ?= cl_abap_typedescr=>describe_by_name( 'spfli' ).
*COMPDESC-TYPE ?= CL_ABAP_DATADESCR=>DESCRIBE_BY_NAME( 'EKPO-MATNR' ).
DATA: datatype TYPE REF TO cl_abap_datadescr,
field(5) TYPE c.
datatype ?= cl_abap_typedescr=>describe_by_data( field ).
DATA: elemtype TYPE REF TO cl_abap_elemdescr.
elemtype = cl_abap_elemdescr=>get_i( ).
elemtype = cl_abap_elemdescr=>get_c( 20 ).
DATA: oref1 TYPE REF TO object.
DATA: descr_ref1 TYPE REF TO cl_abap_typedescr.
CREATE OBJECT oref1 TYPE ('C1'). "C1爲類名
descr_ref1 = cl_abap_typedescr=>describe_by_object_ref( oref1 ).
還有一種:describe_by_data_ref
handle只能是CL_ABAP_DATADESCR或其子類的引用變量,注:只能用於Data類型,不能用於Object類型,即不能用於CL_ABAP_ OBJECTDESCR,因此沒有:
CREATE OBJECT dref TYPE HANDLE objectDescr.
DATA: dref TYPE REF TO data,
c10type TYPE REF TO cl_abap_elemdescr.
c10type = cl_abap_elemdescr=>get_c( 10 ).
CREATE DATA dref TYPE HANDLE c10type.
DATA: x20type TYPE REF TO cl_abap_elemdescr.
x20type = cl_abap_elemdescr=>get_x( 20 ).
FIELD-SYMBOLS: <fs> TYPE any.
ASSIGN dref->* TO <fs> CASTING TYPE HANDLE x20type.
TYPES: ty_i TYPE i.
DATA: dref TYPE REF TO ty_i .
CREATE DATA dref TYPE ('I')."根據基本類型名動態建立數據
dref->* = 1.
WRITE: / dref->*." 1
CREATE OBJECT oref TYPE ('C1')."根據類名動態建立實例對象
DATA: dref_str TYPE REF TO data,
dref_tab TYPE REF TO data,
dref_i TYPE REF TO data,
itab_type TYPE REF TO cl_abap_tabledescr,
struct_type TYPE REF TO cl_abap_structdescr,
elem_type TYPE REF TO cl_abap_elemdescr,
table_type TYPE REF TO cl_abap_tabledescr,
comp_tab TYPE cl_abap_structdescr=>component_table WITH HEADER LINE.
FIELD-SYMBOLS :<fs_itab> TYPE ANY TABLE.
**=========動態建立基本類型
elem_type ?= cl_abap_elemdescr=>get_i( ).
CREATE DATA dref_i TYPE HANDLE elem_type ."動態的建立基本類型數據對象
**=========動態建立結構類型
struct_type ?= cl_abap_typedescr=>describe_by_name( 'SFLIGHT' )."結構類型
comp_tab[] = struct_type->get_components( )."組成結構體的各個字段組件
* 向結構中動態的新增一個成員
comp_tab-name = 'L_COUNT'."爲結構新增一個成員
comp_tab-type = elem_type."新增成員的類型對象
INSERT comp_tab INTO comp_tab INDEX 1.
* 動態建立結構類型對象
struct_type = cl_abap_structdescr=>create( comp_tab[] ).
CREATE DATA dref_str TYPE HANDLE struct_type."使用結構類型對象來建立結構對象
**=========動態建立內表
* 基於結構類型對象建立內表類型對象
itab_type = cl_abap_tabledescr=>create( struct_type ).
CREATE DATA dref_tab TYPE HANDLE itab_type."使用內表類型對象來建立內表類型
ASSIGN dref_tab->* TO <fs_itab>."將字段符號指向新建立出來的內表對象
"**========給現有的內表動態的加一列
table_type ?= cl_abap_tabledescr=>describe_by_data( itab ).
struct_type ?= table_type->get_table_line_type( ).
comp_tab[] = struct_type->get_components( ).
comp_tab-name = 'FIDESC'.
comp_tab-type = cl_abap_elemdescr=>get_c( 120 ).
INSERT comp_tab INTO comp_tab INDEX 2.
struct_type = cl_abap_structdescr=>create( comp_tab[] ).
itab_type = cl_abap_tabledescr=>create( struct_type ).
CREATE DATA dref_tab TYPE HANDLE itab_type.
CLASS c1 DEFINITION.
PUBLIC SECTION.
DATA: c VALUE 'C'.
METHODS: test.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD:test.
WRITE:/ 'test'.
ENDMETHOD.
ENDCLASS.
START-OF-SELECTION.
TYPES: ty_c.
DATA: oref TYPE REF TO object .
DATA: oref_classdescr TYPE REF TO cl_abap_classdescr .
CREATE OBJECT oref TYPE ('C1')."根據類名動態建立實例對象
"至關於Java中的Class類對象
oref_classdescr ?= cl_abap_classdescr=>describe_by_object_ref( oref ).
DATA: t_attrdescr_tab TYPE abap_attrdescr_tab WITH HEADER LINE,"類中的屬性列表
t_methdescr_tab TYPE abap_methdescr_tab WITH HEADER LINE."類中的方法列表
FIELD-SYMBOLS <fs_attr> TYPE any.
t_attrdescr_tab[] = oref_classdescr->attributes.
t_methdescr_tab[] = oref_classdescr->methods.
LOOP AT t_attrdescr_tab."動態訪問類中的屬性
ASSIGN oref->(t_attrdescr_tab-name) TO <fs_attr>.
WRITE: / <fs_attr>.
ENDLOOP.
LOOP AT t_methdescr_tab."動態訪問類中的方法
CALL METHOD oref->(t_methdescr_tab-name).
ENDLOOP.
CLASS class DEFINITION [ABSTRACT][FINAL].
[PUBLIC SECTION.
[components]]
[PROTECTED SECTION.
[components]]
[PRIVATE SECTION.
[components]]
ENDCLASS.
INTERFACE intf.
[components]
ENDINTERFACE.
²TYPES, DATA, CLASS-DATA, CONSTANTS for data types and data objects
²METHODS, CLASS-METHODS, EVENTS, CLASS-EVENTS for methods and events
² INTERFACES(若是在類中,表示須要實現哪一個接口;若是是在接口中,表示繼承哪一個接口) for implementing interfaces
² ALIASESfor alias names for interface components給接口組件取別名
CLASS math DEFINITION.
PUBLIC SECTION.
METHODS divide_1_by
IMPORTING operand TYPE i
EXPORTING result TYPE f
RAISING cx_sy_arithmetic_error.
ENDCLASS.
CLASS math IMPLEMENTATION.
METHOD divide_1_by.
result = 1 / operand.
ENDMETHOD.
ENDCLASS.
INTERFACEint1.
ENDINTERFACE.
CLASSclass DEFINITION. [ˌdefiˈniʃən]
PUBLICSECTION.
INTERFACES: int1,int2."可實現多個接口
ENDCLASS.
CLASS class IMPLEMENTATION. [ˌɪmplɪmənˈteɪ-ʃən]
METHOD intf1~imeth1.
ENDMETHOD.
ENDCLASS.
CLASS<subclass> DEFINITIONINHERITINGFROM<superclass>.
INTERFACE i0.
METHODS m0.
ENDINTERFACE.
INTERFACE i1.
INTERFACES i0.
"能夠有相同的成員名,由於繼承過來後,成員仍是具備各自的命名空間,在實現時
"被繼承過來的叫 i0~m0,在這裏的名爲i1~m0,因此是不一樣的兩個方法
METHODS m0.
METHODS m1.
ENDINTERFACE.
CLASS person DEFINITION.
ENDCLASS.
CLASS stud DEFINITION INHERITING FROMperson.
ENDCLASS.
START-OF-SELECTION.
DATA p TYPE REF TO person.
DATA s TYPE REF TO stud.
CREATE OBJECT s.
p = s. "向上自動轉型
"拿開註釋運行時拋異常,由於P此時指向的對象不是Student,而是Person因此能強轉的前提是P指向的是Student
"CREATE OBJECT p.
METHODS/CLASS-METHODS meth [ABSTRACT|FINAL]
[IMPORTING parameters [PREFERRED PARAMETER p]]
[EXPORTING parameters]
[CHANGING parameters]
[{RAISING|EXCEPTIONS} exc1 exc2 ...].
應該還有一個Returning選項,且RETURNING不能與EXPORTING、CHANGING同時使用:
... { VALUE(p1) | REFERENCE(p1) | p1 }
{ TYPE generic_type }
|{TYPE{[LINE OF] complete_type}|{REF TO {data|object|complete_type |class|intf}}}
|{LIKE{[LINE OF] dobj}|{REF TO dobj} }
[OPTIONAL|{DEFAULT def1}]
{ VALUE(p2) | REFERENCE(p2) | p2 }...
²data、object:表示是通用數據類型data、object
²complete_type:爲徹底限定類型
²OPTIONAL與DEFAULT兩個選項不能同時使用,且對於EXPORTING類型的輸入參數不能使用
²若是參數名p1前沒有使用VALUE、REFERENCE,則默認爲仍是REFERENCE,即引用傳遞
²方法中的輸入輸出參數是否能修改,請參考Form、Function參數的傳值傳址
設置多個IMPORTING類型參數中的某一個參數爲首選參數。
首選參數的意義在於:當全部IMPORTING類型都爲可選optional時,咱們能夠經過PREFERRED PARAMETER選項來指定某一個可選輸入參數爲首選參數,則在如下簡單方式調用時:[CALL METHOD] meth( a ). 實參a的值就會傳遞給設置的首選參數,而其餘不是首參數的可選輸入參數則留空或使用DEFAULT設置的默認值
注:此選項只能用於IMPORTING類型的參數;若是有必選的IMPORTING輸入參數,則沒有意義了
[CALL METHOD] meth|me->meth|oref->meth|super->meth|class=>meth[(]
[EXPORTING p1 = a1 p2 = a2 ...]
{ {[IMPORTING p1=a1 p2=a2 ...][CHANGING p1 = a1 p2 = a2 ...]}
|[RECEIVING r = a ] } RECEIVING不能與EXPORTING、CHANGING同時使用
[EXCEPTIONS [exc1 = n1 exc2 = n2 ...]
[OTHERS = n_others] ] [)].
若是省略CALL METHOD,則必定要加上括號形式;若是經過CALL METHOD來調用,則括號可加可不加
RECEIVING:用來接收METHODS /CLASS-METHODS 中RETURNING選項返回的值
若是EXPORTING、IMPORTING、CHANGING、RECEIVING、EXCEPTIONS、OTHERS同時出現時,應該按此順序來編寫
注:使用此種方式調用(使用 EXPORTING、IMPORTING等這些選項)時,若是原方法聲明時帶了返回值RETURNING,只能使用RECEIVING來接受,而不能使用等號來接收返回值,下面用法是錯誤的:
num2 = o1->m1( EXPORTING p1 = num1 ).
此方式下輸入的參數都只能是IMPORTING類型的參數,若是要傳CHANGING、EXPORTING、RAISING、EXCEPTIONS類型的參數時,只能使用上面通用調用方式。
²meth( )
此種方式僅適用於沒有輸入參數(IMPORTING)、輸入\輸出參數(CHANGING)、或者有但都是可選的、或者不是可選時但有默認值也可
²meth( a )
此種方式僅適用於只有一個必選輸入參數(IMPORTING)(若是還有其餘輸入參數,則其餘都爲可選,或者不是可選時但有默認值也可),或者是有多個可選輸入參數(IMPORTING)(此時沒有必選輸入參數狀況下)的狀況下但方法聲明時經過使用PREFERRED PARAMETER選項指定了其中某個可選參數爲首選參數(首選參數即在使用meth( a )方式傳遞一個參數進行調用時,經過實參a傳遞給設置爲首選的參數)
²meth( p1 = a1 p2 = a2 ... )
此種方式適用於有多個必選的輸入參數(IMPORTING)方法的調用(其它如CHANGING、EXPORTING沒有,或者有但可選),若是輸入參數(IMPORTING)爲可選,則也能夠沒必要傳
Return惟一返回值
METHODS meth
[IMPORTING parameters [PREFERRED PARAMETER p]]
RETURNINGVALUE(r) typing
[{RAISING|EXCEPTIONS} exc1 exc2 ...].
RETURNING :用來替換EXPORTING、CHANGING,不能同時使用。定義了一個形式參數 r 來接收返回值,而且只能是值傳遞
具備惟一返回值的函數方法能夠直接用在如下語句中:邏輯表達式(IF、ELSEIF、WHILE、CHECK、WAIT)、CASE、LOOP、算術表達式、賦值語句
函數方法能夠採用上面簡單調用方式來調用:meth( )、meth( a )、meth( p1 = a1 P2 = a2 ... )
ref->m( RECEIVING r = i ).
CALL METHOD ref->m( RECEIVING r = i ).
CALL METHOD ref->m RECEIVING r = i.
等效於Java中的 this、super
EVENTS|CLASS-EVENTS evt [EXPORTING VALUE(p1)
{ TYPE generic_type }
|{TYPE {[LINE OF] complete_type} |
{ REF TO {data|object|complete_type|class|intf}} }
| {LIKE{[LINE OF] dobj} | {REF TO dobj} }
[OPTIONAL|{DEFAULT def1}]
VALUE(p2) ...].
²data、object:表示是通用數據類型data、object
²complete_type:爲徹底限定類型
² OPTIONAL與DEFAULT兩個選項不能同時使用
²EXPORTING:定義了事件的輸出參數,而且事件定義時只能有輸出參數,且只能是傳值
非靜態事件聲明中除了明確使用EXPORTING定義的輸出外,每一個實例事件其實還有一個隱含的輸出參數sender,它指向了事件源對象,當使用RAISE EVENT語句觸發一個事件時,事件源的對象就會分配給這個sender引用,可是靜態事件沒有隱含參數sender
事件evt的定義也是在類或接口的定義部分進行定義的
非靜態事件只能在非靜態方法中觸發,而不能在靜態方法中觸發;而靜態事件便可在靜態也可在非靜態方法中進行觸發,或者反過來講:實例方法既可觸發靜態事件,也可觸發非靜態事件,但靜態方法就只能觸發靜態事件
RAISE EVENT evt [EXPORTING p1 = a1 p2 = a2 ...].
該語句只能在定義evt事件的同一類或子類,或接口實現方法中進行調用
當實例事件觸發時,若是在event handler事件處理器聲明語句中指定了形式參數sender,則會自動接收事件源,但不能在RAISE EVENT …EXPORTING語句中明確指定,它會自動傳遞(若是是靜態事件,則不會傳遞sender參數)
CLASS c1 DEFINITION.
PUBLIC SECTION.
EVENTS e1 EXPORTING value(p1) TYPE string value(p2) TYPE i OPTIONAL. "定義
METHODS m1.
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD m1.
RAISE EVENT e1 EXPORTING p1 = '...'."觸發
ENDMETHOD.
ENDCLASS.
靜態或非靜態事件處理方法均可以處理靜態或非靜態事件,與事件的靜態與否沒有直接的關係
INTERFACE window. "窗口事件接口
EVENTS: minimize EXPORTINGVALUE(status) TYPE i."最小化事件
ENDINTERFACE.
CLASS dialog_window DEFINITION. "窗口事件實現
PUBLIC SECTION.
INTERFACES window.
ENDCLASS.
INTERFACE window_handler. "窗口事件處理器接口
METHODS: minimize_window FOR EVENT window~minimize OF dialog_window
IMPORTING status sender. "事件處理器方法參數要與事件接口定義中的一致
ENDINTERFACE.
實例事件處理器(方法)註冊(注:被註冊的方法只能是用來處理非靜態事件的方法):
SET HANDLER handler1 handler2 ... FOR oref|{ALL INSTANCES}[ACTIVATION act].
靜態事件處理器(方法)註冊(注:被註冊的方法只能是用來處理靜態事件的方法):
SET HANDLER handler1 handler2 ... [ACTIVATION act].
oref:只將事件處理方法handler1 handler2註冊到 oref 這一個事件源對象
ALL INSTANCES:將事件處理方法註冊到全部的事件源實例中
ACTIVATION act:表示是註冊仍是註銷
CLASS c1 DEFINITION."事件源
PUBLIC SECTION.
EVENTS: e1 EXPORTING value(p1) TYPE c,e2.
CLASS-EVENTS ce1 EXPORTING value(p2) TYPE i.
METHODS:trigger."事件觸發方法
ENDCLASS.
CLASS c1 IMPLEMENTATION.
METHOD trigger.
RAISE EVENT: e1 EXPORTING p1 = 'A',e2,ce1 EXPORTING p2 = 1.
ENDMETHOD.
ENDCLASS.
靜態(以下面的h1方法)或非靜(以下面的h2方法)態事件處理方法均可以處理靜態或非靜態事件,事件的處理方法是否只能處理靜態的仍是非靜態事件與事件的靜態與否沒有關係,但事件的觸發方法與事件的靜態與否有關係(實例方法既可觸發靜態事件,也可觸發非靜態事件,但靜態方法就只能觸發靜態事件);可是,事件處理方法雖然能處理的事件與事件的靜態與否沒有關係,但若是處理的是靜態事件,那此處理方法就成爲了靜態處理器,只能採用靜態註冊方式對此處理方法進行註冊。若是處理的是非靜態事件,那此處理方法就是非靜態處理器,只能採用非靜態註冊方式對此處理方法進行註冊
處理器的靜態與否與處理方法自己是否靜態沒有關係,只與處理的事件是否靜態有關
CLASS c2 DEFINITION."監聽器:即事件處理器
PUBLIC SECTION.
"靜態方法也能夠處理非靜態事件,此方法屬於非靜態處理器,只能採用非靜態註冊方式
CLASS-METHODS h1 FOR EVENT e1 OF c1 IMPORTING p1 sender.
"非靜態方法處理非靜態事件,此方法屬於非靜態處理器,只能採用非靜態註冊方式
METHODS: h2 FOR EVENT e2 OF c1 IMPORTING sender,
"非靜態方法固然更能夠處理靜態事件,此方法屬於靜態處理器,只能採用靜態註冊方式
h3 FOR EVENT ce1 OF c1 IMPORTING p2.
ENDCLASS.
CLASS c2 IMPLEMENTATION.
METHOD h1 .
WRITE: 'c2=>h1'.
ENDMETHOD.
METHOD: h2.
WRITE: 'c2->h2'.
ENDMETHOD.
METHOD: h3.
WRITE: 'c2->h3'.
ENDMETHOD.
ENDCLASS.
DATA: trigger TYPE REF TO c1,
trigger2 TYPE REF TO c1,
handler TYPE REF TO c2.
START-OF-SELECTION.
CREATE OBJECT trigger.
CREATE OBJECT trigger2.
CREATE OBJECT handler.
"因爲h1、h2兩個處理方法分別是用來處理非靜態事件e1、e2的,因此只能採用實例註冊方式
SET HANDLER: c2=>h1 handler->h2 FOR trigger,
"h3處理方法是用來處理靜態事件ce1的,屬於靜態處理器,因此只能採用靜態註冊方式
handler->h3.
trigger->trigger( ).
"雖然trigger( )方法會觸發 e1,e2,ce1 三種事件,但h1、h2未向實例trigger2註冊,而h3屬於靜態處理器,與實例無關,即比如向全部實例註冊過了同樣
trigger2->trigger( ).
LOOP AT itab {INTO wa}|{ASSIGNING <fs> [CASTING]}|{TRANSPORTING NO FILDS}
[[USING KEY key_name|(name)] [FROM idx1] [TO idx2] [WHERE log_exp|(cond_syntax)]].
ENDLOOP.
FROM … TO: 只適用於標準表與排序表 WHERE … : 適用於全部類型的內表
若是沒有經過USING KEY選項的key_name,則循環讀取的順序與表的類型相關:
l標準表與排序表:會按照primary table index索引的順序一條條的循環,且在循環裏SY-TABIX爲當前正在處理行的索引號
l 哈希表:因爲表沒有排序,因此按照插入的順序來循環處理,注,此時SY-TABIX 老是0
能夠在循環內表時增長與刪除當前行:If you insert or delete lines in the statement block of a LOOP , this will have the following effects:
DATA : BEGIN OF gt_table OCCURS 0,
c,
END OF gt_table.
APPEND 'a' TO gt_table.
APPEND 'b' TO gt_table.
APPEND 'c' TO gt_table.
APPEND 'd' TO gt_table.
APPEND 'e' TO gt_table.
APPEND 'f' TO gt_table.
APPEND 'g' TO gt_table.
APPEND 'h' TO gt_table.
LOOP AT gt_table .
IF gt_table-c = 'b' OR gt_table-c = 'c' OR gt_table-c = 'e'.
WRITE : / sy-tabix COLOR = 6 INTENSIFIED ON INVERSE OFF ,
gt_table COLOR = 6 INTENSIFIED ON INVERSE OFF .
ELSE.
WRITE : / sy-tabix, gt_table.
ENDIF.
ENDLOOP.
SKIP 2.
DATA count TYPE i .
LOOP AT gt_table .
count = count + 1.
"當循環到第三次時刪除,即循環到 C 時進行刪除
IF count = 3.
DELETE gt_table WHERE c = 'b' OR c = 'c' OR c = 'e'.
ENDIF.
"刪除以後sy-tabix會從新開始對內表現有的行進行編號
WRITE :/ sy-tabix, gt_table.
ENDLOOP.
SKIP 2.
LOOP AT gt_table .
WRITE : / sy-tabix, gt_table.
ENDLOOP.
若是在 AT - ENDAT 塊中使用 SUM,則系統計算當前行組中全部行的數字字段之和並將其寫入工做區域中相應的字段中
<line> |
含義 |
FIRST |
內表的第一行時觸發 |
LAST |
內表的最後一行時觸發 |
NEW <f> |
相鄰數據行中相同<f>字段構成一組,在循環到該組的開頭時觸發 |
END Of <f> |
相鄰數據行中相同<f>字段構成一組,在循環到該組的最末時觸發 |
在使用AT...... ENDAT以前,一這要先按照這些語句中的組件名進行排序,且排序的順序要與在AT...... ENDAT語句中使用順序一致,排序與聲明的順序決定了先按哪一個分組,接着再按哪一個進行分組,最後再按哪一個進行分組,這與SQL中的Group By 類似
用在AT...... ENDAT語句中的中的組件名不必定要是結構中的關鍵字段,但這些字段必定要按照出如今AT關鍵字後面的使用順序在結構最前面進行聲明,且這些組件字段的聲明之間不能插入其餘組件的聲明。如如今須要按照<f1>, <f2>, ....多個字段的順序來使用在AT...... ENDAT語句中,則首先須要在結構中按照<f1>, <f2>, ....,多字段的順序在結構最前面都聲明,而後按照<f1>, <f2>, ....,多字段來排序的,最後在循環中按以下的順序塊書寫程序(請注意書寫AT END OF的順序與AT NEW 是相反的,像下面這樣):
LOOP AT <itab>.
AT FIRST. ... ENDAT.
AT NEW <f1>. ...... ENDAT.
AT NEW <f2>. ...... ENDAT.
.......
<single line processing>
.......
AT END OF <f2>.... ENDAT.
AT END OF <f1>. ... ENDAT.
AT LAST. .... ENDAT.
ENDLOOP.
一旦進入到 AT...<f1>...ENDAT 塊中時,當前工做區(或表頭)中的從<f1>日後,但不包括<f1>(按照在結構中聲明的次序)全部字段的字符類型字段會以星號(*)號來填充,而數字字設置爲初始值(注:在測試過程當中發現String類型不會使用*來填充,而是設置成empty String,因此只有固定長度類型的非數字基本類型才設置爲*)。若是在 AT 塊中使用了SUM,則會將全部數字類型字段統計出來將存入當前工做區(或表頭);但一旦離開AT....ENDAT塊後,又會將當前遍歷的行恢復到工做區(或表頭)中
DATA: BEGIN OF th_mseg OCCURS 10,
matnr TYPE mard-matnr, werks TYPE mard-werks,
lgort TYPE mard-lgort, shkzg TYPE mseg-shkzg,
menge TYPE mseg-menge, budat TYPE mkpf-budat,
LOOP AT th_mseg.
AT END OF shkzg."會根據shkzg及前面全部字段來進行分組
sum.
WRITE: / th_mseg-matnr, th_mseg-werks,th_mseg-lgort,
th_mseg-shkzg,th_mseg-menge,th_mseg-budat.
ENDAT.
ENDLOOP.
AS-101 2300 0001 S 10.000 ****.**.**
AS-100 2300 0002 S 10.000 ****.**.**
AS-100 2300 0001 S 20.000 ****.**.**
上面因爲沒有根據matnr + werks + lgort + shkzg 進行排序,因此結果中的第三行其實應該與第一行合併。其實這個統計與SQL裏的分組(Group By)統計原理是同樣的,Group By 後面須要明確指定分組的字段,如上面程序使用SQL分組寫法應該爲 Group Bymatnr werks lgort shkzg,但在ABAP裏你只須要按照 matnr werks lgort shkzg按照前後順序在結構定義的最前面進行聲明就可表達了Group By那種意義,並且不必定要將matnr werks lgort shkzg這四個字段所有用在AT語句塊中AT NEW、AT END OF shkzg 才正確,其實像上面程序同樣,只寫AT END OF shkzg這一個語句,前面三個字段matnr werks lgort均可以不用在AT語句中出現,由於ABAP默認會按照結構中聲明的順序將shkzg前面的字段也全都用在了分組中了
DATA: BEGIN OF line,
"C2、C3組件名聲明的順序必定要與在AT...... ENDAT塊中使用的次序一致,即這裏不能將C3聲明在C2以前,且不能在C2與C3之間插入其餘字段的聲明
c2(5) TYPE c,
c3(5) TYPE c,
c4(5) TYPE c,
i1 TYPE i,
i2 TYPE i,
c1(5) TYPE c,
END OF line.
"使用在AT...... ENDAT語句中的字段不必定要是關鍵字段
DATA: itab LIKE TABLE OF line WITH HEADER LINE WITH NON-UNIQUE KEY i1.
PERFORM append USING 2 'b' 'bb' 'bbb' '2222' 22.PERFORM append USING 3 'c' 'aa' 'aaa' '3333' 33.
PERFORM append USING 4 'd' 'aa' 'bbb' '4444' 44.PERFORM append USING 5 'e' 'bb' 'aaa' '5555' 55.
PERFORM append USING 6 'f' 'bb' 'bbb' '6666' 66.PERFORM append USING 7 'g' 'aa' 'aaa' '7777' 77.
PERFORM append USING 8 'h' 'aa' 'bbb' '8888' 88.
SORT itab ASCENDING BY c2 c3.
LOOP AT itab.
WRITE: / itab-c2,itab-c3,itab-c1,itab-c4,itab-i1,itab-i2.
ENDLOOP.
SKIP.
LOOP AT itab.
AT FIRST.
WRITE:/ '>>>> AT FIRST'.
ENDAT.
AT NEW c2.
WRITE: / ' >>>> Start of' , itab-c2.
ENDAT.
AT NEW c3.
WRITE: / ' >>>> Start of' , itab-c2, itab-c3.