無為

          無為則可為,無為則至深!

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            190 Posts :: 291 Stories :: 258 Comments :: 0 Trackbacks

          JavaFX Script™ (下文中成為JavaFX)語言是一種聲明式的靜態類型編程語言。它具有第一級函數(first-class functions)、聲明式的語法、列表推導(list-comprehensions)及基于依賴關系的增量式求值(incremental dependency-based evaluation)等特征。JavaFX 腳本式語言特別適用于Java2D swing GUI組件,它允許簡單地創建圖形界面。

          譯者注:第一級函數指函數被當作對象對待,可以在運行時賦值、傳遞和返回。詳見wikipedia上的解釋。

          譯者注:列表推導指一種在函數語言中的表達式,它表示了在一個或者多個列表的成員(被選擇的)進行某種操作的結果。它被稱為“syntactic sugar”,即為開發者提供了便捷的多種函數的應用組合。詳見FOLDC對list comprehension的解釋。

          本文檔給出了JavaFX 腳本式編程語言的非正式描述。

          內容:

          top

          JavaFX語言提供四種基本類型:String(字符串)、Boolean(布爾)、Number(數值)Integer(整數)。這些類型相當于Java的如下類型:


          JavaFX Java
          String java.lang.String
          Boolean java.lang.Boolean
          Number java.lang.Number
          Integer byte,short,int,long,BigInteger

          例如:

          	var s = "Hello";
          s.toUpperCase(); // yields "HELLO";
          s.substring(1); // yields "ello";
          var n = 1.5;
          n.intValue(); // yields 1
          (1.5).intValue(); // yields 1
          s.substring(n); // yields "ello"
          var b = true;
          b instanceof Boolean; // yields true

          在向Java方法傳遞參數或者從Java方法返回結果的時候,數值類型會自動執行強制類型轉換。并且,在轉換NumberInteger的時候還會進行隱式的強制截斷。

          top

          調用Java對象

          JavaFX可以導入Java類、創建新的Java對象、調用它們的方法,也可以實現Java的接口。下面的代碼片斷提供了一個示例:

                  
          import javax.swing.JFrame;
          import javax.swing.JButton;
          import java.awt.event.ActionListener;
          import java.lang.System;

          var frame = new JFrame();
          var button = new JButton("Press me");
          frame.getContentPane().add(button);
          button.addActionListener(new ActionListener() {
          operation actionPerformed(event) {
          System.out.println("You pressed me");
          }
          });
          frame.pack();
          frame.setVisible(true);
          運行上面的程序后,屏幕上顯示如下內容:
          Image of simple frame window with press me button.

          當然,這并不是JavaFX推薦的創建圖形用戶界面的方式。下面的JavaFX代碼實現了相同的效果:

                   
          Frame {
          content: Button {
          text: "Press Me"
          action: operation() {
          System.out.println("You pressed me");
          }
          }
          visible: true
          }

          top

          變量

          在JavaFX中,var這個關鍵詞用來聲明變量。你可以在聲明中指定變量的類型。然而,這在JavaFX中是可選的。如果你不指定類型,JavaFX解釋器會根據它的用途推斷變量的類型。變量聲明使用如下格式:

                  var variableName : typeName [?,+,*] = initializer;
          你可以使?、+或者*操作表示變量的重數(cardinality),如下表:


          操作符 含義
          ? Optional (i.e, may be null)
          + One or more
          * Zero or more

          例如:

                  var nums:Number* = [1,2,3];

          上面的示例聲明了一個新的、名為nums的變量,它值由零個或者多個Number類型組成,其初始值為[1,2,3]

          :typeName[?,+,*]以及=initializer這些聲明部分是可選的,所以下面的方式與上面等價:
          	var nums = [1,2,3];

          top

          函數、數組、表達式和操作

          JavaFX函數代表了JavaFX編程語言的純函數子集。函數體可以僅包含一組變量聲明和一個返回語句。JavaFX也提供了過程(procedures)(被調用的操作,詳見下面關于操作的章節),里面可以包括任意數量的聲明、條件語句、循環條件、try/catch等等。語句在函數中的給定順序并不很重要。下面是一個簡單的函數程序的例如:

          	function z(a,b) {
          var x = a + b;
          var y = a - b;
          return sq(x) / sq (y);
          }

          function sq(n) {return n * n;}

          function main() {
          return z(5, 10);
          }

          盡管JavaFX語言是靜態類型的,但這里并沒有強制的類型聲明(后面會詳細敘述)。

          最常用的數據結構是數組,它在JavaFX中通過方括弧和逗號來聲明:
          	var week_days = ["Mon","Tue","Wed","Thur","Fri"];
          var days = [week_days, ["Sat","Sun"]];

          數組代表了一組順序的對象。JavaFX中的數組本身不是對象,而且不能嵌套。創建嵌套數組的表達式(例如上面“days”的初始化方式)會被自動扁平化,例如:

          	days == ["Mon","Tue","Wed","Thur","Fri","Sat","Sun"]; // returns true

          數組的大小可以通過JavaFX的sizeof操作符確定:

          	var n = sizeof days; // n = 7
          對于數組成員形成數列(arithmetic series)的數組,JavaFX提供了一種簡寫符號:“..”。下面提供了定義階乘函數和奇數求和函數的示例,其中“result”的數值是1至100中奇數的和:
          	function fac(n) {return product([1..n]);}
          var result = sum([1,3..100]);

          數組中的所有元素必須是同一種類型。

          數組可以像在Java中那樣通過索引訪問:

                  var wednesday = days[2];
          JavaFX中的[]操作符還可用來表示選擇(類似XPath的用法)。在這種情況下,[]中包含的表達式應是一個布爾表達式。此表達式可以返回一個新的數組,此數組中只包含滿足[]中斷言(predicate)的成員。

          就像在XPath一樣,可以在[]操作符包含的斷言中通過.操作符訪問上下文對象。例如:

          	var nums = [1,2,3,4];
          var numsGreaterThanTwo = nums[. > 2]; // yields [3, 4]

          另一種方法,也可以將變量聲明為上下文對象。例如,這種方式與上面的方式等價:

          	numsGreaterThanTwo = nums[n|n > 2];

          JavaFX中的indexof操作符返回對象在數組中的順序位置(類似XPath中的position()函數)。

          下面list的car和cdr可以用選擇表達式來表示:

          	function car(list) {return list[indexof . == 0];}
          function cdr(list) {return list[indexof . > 0];}

          當然,car可以用更簡單、高效的方式表示:

          	function car(list) {return list[0];}

          例如:

          	var list = [1..10];
          car(list); // yields 1
          cdr(list); // yields [2,3,4,5,6,7,8,9,10]

          JavaFX中的空數組[]null等價,例如:

          	[] == null // yields true
          sizeof null // yields 0

          top

          修改數組

          除了賦值操作(=)之外,JavaFX還提供數據修改操作符(insertdelete),它類似XQuery-Update規范中的語法和語義:

          insert語句

          可以用下面方式中的任意一種進行聲明:

          	insert Expression1 [as first | as last] into Expression2
          insert Expression1 before Expression2
          insert Expression1 after Expression2

          insert語句將表達式1求值后的返回結果插入到下面表達式中所描述的位置:

          into

          表達式2必須指向一個屬性或者變量。如果表達式2指向一個單值屬性,那么插入的效果等同于賦值操作。

          如果指定了as first,那么插入位置就在表達式2所表示的列表的第一個元素的前面。如果指定了as last,那么插入位置就在表達式2所表示的列表的最后一個元素的后面。如果沒有明確地指定as first或者as last,則默認為as last。

          例如:

          	var x = [1,2,3];
          insert 12 into x; // yields [1,2,3,12]
          insert 10 as first into x; // yields [10,1,2,3,12]
          insert [99,100] as last into x; // yields [10,1,2,3,12,99,100]

          before, after

          表達式2必須是在屬性或者變量之上的選擇表達式。如果指定了before,那么插入位置就是在被選擇的元素之前。如果指定了after,插入位置則在被選擇的元素之后。

          例如:

          	var x = [1,2,3];
          insert 10 after x[. == 10]; // yields [1,2,3,10]
          insert 12 before x[1]; // yields [1,12,2,3,10]
          insert 13 after x[. == 2]; // yields [1, 12, 2, 13, 3, 10];

          top

          delete語句

          delete語句可以使用下面形式中的一種:

          	delete variable
          delete Expression.attribute
          delete variable[predicate]
          delete Expression.attribute[predicate]

          前兩種形式將刪除變量或者屬性中的所有元素,它們等價于將變量或者屬性賦值為[]或者null。后兩種形式僅刪除滿足斷言的元素。

          例如:

          	var x = [1,2,3];
          insert 10 into x; // yields [1,2,3,10]
          insert 12 before x[1]; // yields [1,12,2,3,10]
          delete x[. == 12]; // yields [1,2,3,10]
          delete x[. >= 3]; // yields [1,2]
          insert 5 after x[. == 1]; // yields [1,5,2];
          insert 13 as first into x; // yields [13, 1, 5, 2];
          delete x; // yields []

          top

          查詢數組

          像在Miranda、Haskell這些函數式編程語言中一樣,JavaFX支持列表推導(list comprehensions),但是為了使用一種Java程序員更加熟悉、易懂的語法形式進行表達,JavaFX采取了selectforeach操作符。

          這里提供一個例如:

          	class Album {
          attribute title: String;
          attribute artist: String;
          attribute tracks: String*;
          }

          var albums =
          [Album {
          title: "A Hard Day's Night"
          artist: "The Beatles"
          tracks:
          ["A Hard Day's Night",
          "I Should Have Known Better",
          "If I Fell",
          "I'm Happy Just To Dance With You",
          "And I Love Her",
          "Tell Me Why",
          "Can't Buy Me Love",
          "Any Time At All",
          "I'll Cry Instead",
          "Things We Said Today",
          "When I Get Home",
          "You Can't Do That"]
          },
          Album {
          title: "Circle Of Love"
          artist: "Steve Miller Band"
          tracks:
          ["Heart Like A Wheel",
          "Get On Home",
          "Baby Wanna Dance",
          "Circle Of Love",
          "Macho City"]
          }];

          // Get the track numbers of the albums' title tracks

          // using the select operator:

          var titleTracks =
          select indexof track + 1 from album in albums,
          track in album.tracks
          where track == album.title; // yields [1,4]

          // the same expressed using the foreach operator:

          titleTracks =
          foreach (album in albums,
          track in album.tracks
          where track == album.title)
          indexof track + 1; // also yields [1,4]

          列表推導由一個或多個輸入列表,一個可選的過濾器和一個生成器表達式組成。每個源列表與一個變量關聯。列表推導的結果是將生成器應用于滿足過濾器的源列表成員的笛卡爾乘積的子集后得到的新列表。

          譯者注:這里的過濾器指的是where子句。

          列表推導為創建在列表上進行迭代遍歷的通用類提供了一種簡明的語法。

          列表推導的另外一個簡單示例:

          	select n*n from n in [1..100]

          這個列表(順序地)包含1至100的所有數的平方值。注意上面表達式中的“n”是局部變量。

          下面的代碼通過定義計算某個數值的所有因子的函數演示了如何使用過濾器:

          	function factors(n) {
          return select i from i in [1..n/2] where n % i == 0;
          }

          top

          表達式

          JavaFX支持如下操作符:


          操作符 含義 Java等價物

          關系操作符
          == equality ==
          <> inequality !=
          < less than <
          > greater than >
          <= less than or equal <=
          >= greater than or equal >=

          布爾操作符
          and logical and &&
          or logical or ||
          not logical negation !

          算術操作符
          + addition +
          - subtraction; unary negation -
          * multiplication *
          / division /
          % remainder %
          += add and assign +=
          -= subtract and assign -=
          *= multiply and assign *=
          /= divide and assign /=
          %= remainder and assign %=

          其它操作符
          sizeof array length n/a
          indexof ordinal position n/a
          if e1 then e2 else e3 conditional expression e1 ? e2 : e3
          select list comprehension n/a
          foreach list comprehension n/a
          new allocation new
          op() function/operation call n/a
          x.op() member function/operation call x.op()
          instanceof type check instanceof
          this self access this
          . attribute access, context access ., n/a
          bind [lazy] incremental [lazy] evaluation n/a
          : eager initialization n/a
          [] array selection []
          format as String formatting n/a
          <<>> Identifier quotes n/a
          {} String expression n/a
          (expr) grouping (expr)
          reverse reverses a list n/a
          [number1,next..number2] numeric range n/a

          一些示例:

                   
          import java.lang.System;
          import java.lang.Math;

          var x = 2;
          var y = 4;
          var a = true;
          var b = false;
          System.out.println(x == y); // prints false
          System.out.println(x <> y); // prints true
          System.out.println(x < y); // prints true
          System.out.println(x > y); // prints true
          System.out.println(x >= y); // prints false
          System.out.println(x <= y); // prints true
          System.out.println(x + y); // prints 6
          System.out.println(x - y); // prints -2
          System.out.println(x * y); // prints 8
          System.out.println(x / y); // prints 0.5
          System.out.println(x % y); // prints 2
          System.out.println(a and b); // prints false
          System.out.println(a or b); // prints true
          System.out.println(not a); // prints false
          System.out.println(sizeof [x,y]); // prints 2
          System.out.println([x,y][indexof . == 0]); // prints 2
          System.out.println(if a then x else y); // prints 2
          System.out.println(select q from q in [x, y] where q > 3); prints 4
          System.out.println(foreach(q in [x, y] where q < 3) q); prints 2
          System.out.println(Math.max(x, y)); // prints 4
          System.out.println("abc".toUpperCase()); // prints ABC
          System.out.println(x instanceof Number); // prints true
          x = 10;
          System.out.println(x); // prints 10

          top

          字符串和字符串表達式

          在JavaFX中,字符串通過單引號指定,例如:

                  var s = 'Hello';
          或者通過雙引號:
                  var s = "Hello";

          在使用雙引號的情況下,可以使用 {}嵌入JavaFX表達式,例如:

          	var name = 'Joe';
          var s = "Hello {name}"; // s = 'Hello Joe'

          嵌入的表達式自身也可包含使用雙引號引用的字符串(同樣,里面還可以包含更深一級的嵌套表達式),例如:

          	var answer = true;
          var s = "The answer is {if answer then "Yes" else "No"}"; // s = 'The answer is Yes'

          與Java不同,在JavaFX中使用雙引號引用的字符串可以包含換行:

          	var s = "This
          contains
          new lines";

          top

          引用標識符

          在JavaFX中,包含在法語引用符 <<>>里的任何字符串序列(包括空白)被作為標識符。這樣允許你使用像class、variable、function或者屬性名這樣的JavaFX關鍵字(或者其它的一般情況下非法的標識符),例如:

                  var <<while>> = 100;

          它也使調用與JavaFX關鍵字同名的Java方法稱為可能,例如:

          	import javax.swing.JTextArea;

          var textArea = new JTextArea();
          textArea.<<insert>>("Hello", 0);

          top

          范圍表達式

          如前所述,通過下面的語法你可以定義一個形成數列的數值數組。

          	[number1..number2]
          此表達式定義了一個從number1number2之間(含兩端)的連續整數構成的數組。

          例如:

          	var nums = [0..3];
          System.out.println(nums == [0,1,2,3]); // prints true

          默認情況下,值與值的間隔是1,但是也可以指定不同的間隔,這需要在數列的number1后面寫出下一個數值,并用逗號隔開。例如,下面的表達式定義了一個包含1至10之間奇數的數組。

          	[1,3..10]

          如果number1number2要大,會創建降序的數組:

          	var nums = [3..0];
          System.out.println(nums == [3,2,1,0]); // prints true

          top

          字符串(String)、數值(Number)和日期的格式化

          JavaFX有內建的字符串格式化操作符(format as),語法如下:

          	表達式 format as 指令
          

          format as 操作符支持java.text.DecimalFormat、java.text.SimpleDateFormatjava.util.Formatter的格式化指令:如果格式化指令以%開頭,那么將會使用java.util.Formatter;如果表達式是Number類型,則使用java.text.DecimalFormat;如果表達式是java.util.Date類型,則使用java.text.SimpleDateFormat。指令操作數是一個在語法上的標識符,而不是一個表達式。這就允許了在編譯時靜態檢查指令內容的正確性。

          例如:
          	import java.util.Date;

          100.896 format as <<%f>>; // yields '100.896000'
          31.intValue() format as <<%02X>>; // yields '1F'
          var d = new Date();
          d format as <<yyyy-MM-dd'T'HH:mm:ss.SSSZ>>; // yields '2005-10-31T08:04:31.323-0800'
          0.00123 format as <<00.###E0>>; // yields '12.3E-4'

          top

          操作

          在JavaFX中使用operation關鍵字聲明過程(procedure)。例如:

          	import java.lang.StringIndexOutOfBoundsException;
          operation substring(s:String, n:Number): String {
          try {
          return s.substring(n);
          } catch (e:StringIndexOutOfBoundsException) {
          throw "sorry, index out of bounds";
          }
          }

          在上例中定義了一個稱為“substring”的新過程,它接受兩個參數:第一為字符串類型的參數“s”,第二為Number類型的參數“n”,而返回值為字符串類型。

          除了從前提到的賦值、deleteinsert語句之外,下面的語句也可以在過程體中使用:

          表達式語句

          一個基本的表達式可以被用作一條語句,例如下面示例中的"Hello World!":

                 System.out.println("Hello World!");

          top

          If語句

          JavaFX的if語句用法類似Java,除了大括號必須環繞隨后的子句(除非else子句是另一個if語句)之外。

          例如:

          	if (condition1) {
          System.out.println("Condition 1");
          } else if (condition2) {
          System.out.println("Condition2");
          } else {
          System.out.println("not Condition 1 or Condition 2");
          }

          top

          While語句

          JavaFX的while語句用法與Java類似,除了大括號必須環繞語句體之外。

          例如:

          	var i = 0;
          while (i < 10) {
          if (i > 5) {
          break;
          }
          System.out.println("i = {i}");
          i += 1;
          }

          top

          Try語句

          JavaFX的try語句用法類似Java,但它具有JavaFX變量聲明語法。 注意:在JavaFX中,任意對象都能夠被拋出和捕捉,而并非僅僅是java.lang.Throwable的繼承類。

          例如:

          	try {
          throw "Hello";
          } catch (s:String) {
          System.out.println("caught a String: {s}");
          } catch (any) {
          System.out.println("caught something not a String: {any}");
          } finally {
          System.out.println("finally...");
          }

          top

          For語句

          JavaFX的for語句頭與foreach列表推導操作符(list comprehension operator)使用相同的語法。但是,在下面示例中for語句體處理的是由列表推導生成的成員。

          例如:

          	for (i in [0..10]) {
          System.out.println("i = {i}");
          }

          // print only the even numbers using a filter
          for (i in [0..10] where i % 2 == 0) {
          System.out.println("i = {i}");
          }

          // print only the odd numbers using a range expression
          for (i in [1,3..10]) {
          System.out.println("i = {i}");
          }

          // print the cartesian product
          for (i in [0..10], j in [0..10]) {
          System.out.println(i);
          System.out.println(j);
          }

          top

          Return語句

          JavaFX的return語句與Java相同:

          例如:

          	operation add(x, y) {
          return x + y;
          }

          top

          Throw語句

          JavaFX的throw語句類似Java。但是在JavaFX中能夠拋出任何對象,而不僅僅是java.lang.Throwable的繼承類。

          例如:

          	import java.lang.Exception;

          operation foo() {
          throw new Exception("this is a java exception");
          }

          operation bar() {
          throw "just a string";
          }

          top

          Break和Continue語句

          JavaFX的breakcontinue語句用法Java不同的之處:前者不支持標簽。像在Java中一樣,breakcontinue必須出現在while或者for語句體中。

          例如:

          	operation foo() {
          for (i in [0..10]) {
          if (i > 5) {
          break;
          }
          if (i % 2 == 0) {
          continue;
          }
          System.out.println(i);
          }
          }

          operation bar() {
          var i = 0;
          while (i < 10) {
          if (i > 5) {
          break;
          }
          if (i % 2 == 0) {
          continue;
          }
          System.out.println(i);
          i += 1;
          }
          }

          top

          Do語句

          JavaFX的do語句允許使用者在后臺線程中執行一塊JavaFX代碼,以便AWT事件調度線程繼續處理事件,從而防止UI平臺出現掛起現象。目前,在執行后臺線程時采用java.awt.EventQueue實現了對事件的出/入隊操作。通常情況下,所有的JavaFX代碼都在AWT事件調度線程中執行,只有包含在 do語句體中的語句被允許在另一個線程中執行。這些代碼必須只訪問Java對象,如果需要的話,那些Java對象還必須處理其自身的線程同步。

          例如:

          	import java.net.URL;
          import java.lang.StringBuffer;
          import java.lang.System;
          import java.io.InputStreamReader;
          import java.io.BufferedReader;




          // in the AWT EDT
          var result = new StringBuffer();

          do {
          // now in a background thread
          var url = new URL("http://www.foo.com/abc.xml");
          var is = url.openStream();
          var reader = new BufferedReader(new InputStreamReader(is));
          var line;
          while (true) {
          line = reader.readLine();
          if (line == null) {
          break;
          }
          result.append(line);
          result.append("\n");
          }
          }
          // now back in the EDT
          System.out.println("result = {result}");

          在上面的示例中,在事件調度線程(EDT)中正在執行的那些綠色代碼在do語句(紅色代碼)執行期間將被阻塞。但如果在等待后臺線程完成的期間,一個新的事件調度循環被建立在調用堆棧上,那么在執行do語句的同時這些GUI事件將繼續被處理。不幸的是,由于它能夠引發建立在堆棧上的多重事件調度循環,乃至在糟糕的情況下引起堆棧溢出異常,而目前并沒有一種對此稱得上優秀的解決方案。

          top

          do later

          do語句的第二種形式(do later):它允許在事件調度線程中的語句體內進行異步執行,而不是在后臺線程中執行(此功能由java.awt.EventQueue.invokeLater提供)。顧名思義,do later語句體在事件調度線程執行完成后才被執行。下面是一個例如:

          	import java.lang.System;
          var saying1 = "Hello World!";
          var saying2 = "Goodbye Cruel World!";
          do later {
          System.out.println(saying1);
          }
          System.out.println(saying2);
          運行上面的代碼將產生如下輸出:
          	Goodbye Cruel World!
          Hello World!

          top

          類與對象

          JavaFX中聲明類的語法:在class關鍵字后面跟著類名,接著是可選的extends關鍵字和由逗號分割的基類名列表,一個開放的大括號({),一個屬性列表,函數和操作,一個關閉的大括號(}),在大括號中間的每一個語法邏輯行都使用分號結尾。

          例如:

          	class Person {
          attribute name: String;
          attribute parent: Person inverse Person.children;
          attribute children: Person* inverse Person.parent;
          function getFamilyIncome(): Number;
          function getNumberOfChildren(): Number;
          operation marry(spouse: Person);
          }

          屬性的聲明方式:attribute關鍵字后面跟著屬性名,一個冒號,屬性類型,可選的重數(cardinality)說明(?代表不確定,*代表零個或者更多,+代表一個或者更多),一個可選的、用來說明與類中另一屬性之間雙向關系的反向子句(inverse clause),并使用分號結束。

          	attribute AttributeName : AttributeType Cardinality inverse ClassName.InverseAttributeName;

          如果反向子句出現在對象屬性定義中,那么當此屬性值被修改時JavaFX解釋器將自動更新其反向屬性(根據更新的類型和屬性的重數進行插入、刪除或者替換)。

          多值屬性(例如那些使用*或者+重數描述符聲明的屬性)被表示為數組,并能夠通過[]操作符訪問,并使用insertdelete操作符更新。

          和Java方法不同,所有的JavaFX成員操作體和成員函數體都被定義在類聲明外部,例如:

          	function Person.getNumberOfChildren() {
          return sizeof this.children;
          }

          在類聲明中對操作和函數的聲明都需要對參數和返回值類型進行聲明,而在操作體和函數體的具體定義中則可被忽略。

          top

          屬性聲明

          在JavaFX中可以聲明屬性的初始值。在新建對象上下文中的初始化程序按照聲明順序被逐一求值(見下例的粗體部分):

          	import java.lang.System;

          class X {
          attribute a: Number;
          attribute b: Number;
          }

          attribute X.a = 10;
          attribute X.b = -1;

          var x = new X();
          System.out.println(x.a); // prints 10
          System.out.println(x.b); // prints -1

          還可以通過bind操作將增量式求值表達式(incrementally evaluated expression)聲明為屬性值:

          	import java.lang.System;

          class X {
          attribute a: Number;
          attribute b: Number;
          attribute c: Number;
          }

          attribute X.a = 10;

          attribute X.b = bind a + 10;
          attribute X.c = bind lazy b + 10;


          var x = new X();
          System.out.println(x.a); // prints 10
          System.out.println(x.b); // prints 20
          System.out.println(x.c); // prints 30
          x.a = 5;
          System.out.println(x.a); // prints 5
          System.out.println(x.b); // prints 15
          System.out.println(x.c); // prints 25

          top

          對象聲明

          JavaFX使用由類名、用大括號包含的屬性初始化程序列表構成的說明性語法來完成對象的初始化。每個初始化程序由屬性名、冒號、定義屬性值的表達式(JavaFX也支持在上下文中進行增量式求值,詳見下面的章節)構成:

           	var chris = Person {
          name: "Chris"
          children:
          [Person {
          name: "Dee"
          },
          Person {
          name: "Candice"
          }]
          };

          JavaFX也支持Java對象的初始化語法。你可以象在Java中一樣傳遞參數給類構造器:

          	import java.util.Date;
          import java.lang.System;

          var date1 = new Date(95, 4, 23); // call a java constructor
          var date2 = Date { // create the same date as an object literal
          month: 4
          date: 23
          year: 95
          };
          System.out.println(date1 == date2); // prints true

          JavaFX允許在對象中聲明本地變量。這些變量只在對象本身的范圍內可見。另外,一個引用被初始化對象的變量可以通過var關鍵字聲明為假屬性(pseudo-attribute),就如下例中的child1和child2一樣:

          	var chris = Person {
          var: me
          name: "Chris"
          var child1 = Person {
          name: "Dee"
          parent: me
          }
          var child2 = Person { name: "Candice" }
          children: [child1, child2]
          };

          top

          更新觸發器

          JavaFX類沒有構造器,其屬性也沒有“setter”。作為替代物,JavaFX提供了類似SQL的觸發器(trigger)來為使用者提供處理數據修改事件的能力。

          觸發器使用trigger關鍵字聲明。

          觸發器由頭部和代碼體構成。頭部說明了觸發器應用的事件類型。代碼體則是在特定事件發生時執行的過程。在代碼體中你可以使用任何在操作體中有效的語句。與成員函數/操作類似,在觸發器中在代碼體內的上下文對象可以通過this關鍵字訪問。

          top

          創建觸發器

          你可以在一個新建對象的上下文中聲明一個創建觸發器:

           	import java.lang.System;

          class X {
          attribute nums: Number*;
          }

          trigger on new X {
          insert [3,4] into this.nums;
          }

          var x = new X();
          System.out.println(x.nums == [3,4]); // prints true

          上面的示例中定義了一個在X類的實例被創建時執行的觸發器。此觸發器完成了對nums屬性的初始賦值。

          top

          插入觸發器

          當一個成員被插入到多值屬性時,我們可以定義一個插入觸發器:

          	import java.lang.System;

          class X {
          attribute nums: Number*;
          }

          trigger on insert num into X.nums {
          System.out.println("just inserted {num} into X.nums at position {indexof num}");
          }
          var x = new X();
          insert 12 into x.nums; // prints just inserted 12 into X.nums at position 0
          insert 13 into x.nums; // prints just inserted 13 into X.nums at position 1

          以上示例代碼中,“num”是引用被插入成員的變量(你可以按照自己喜好命名它)。此變量的上下文索引(由indexof操作符返回)與插入點一致。

          top

          刪除觸發器

          當一個成員從多值屬性中被刪除時,我們可以定義一個刪除觸發器:

           	import java.lang.System;

          class X {
          attribute nums: Number*;
          }

          trigger on delete num from X.nums {
          System.out.println("just deleted {num} from X.nums at position {indexof num}");
          }

          var x = X {
          nums: [12, 13]
          };

          delete x.nums[1]; // prints just deleted 13 from X.nums at position 1
          delete x.nums[0]; // prints just deleted 12 from X.nums at position 0

          以上示例代碼中,“num”是引用被刪除成員的變量(你可以按照自己喜好命名它)。此變量的上下文索引(由indexof操作符返回)與刪除點一致。

          top

          替換觸發器

          當一個單值的屬性值或者多值屬性的成員被替換時,我們可以定義一個替換觸發器:

          	import java.lang.System;

          class X {
          attribute nums: Number*;
          attribute num: Number?;
          }

          trigger on X.nums[oldValue] = newValue {
          System.out.println("just replaced {oldValue} with {newValue} at position {indexof newValue} in X.nums");
          }

          trigger on X.num[oldValue] = newValue {
          System.out.println("X.num: just replaced {oldValue} with {newValue}");
          }

          var x = X {
          nums: [12, 13]
          num: 100
          };
          x.nums[1] = 5; // prints just replaced 13 with 5 at position 1 in X.nums
          x.num = 3; // prints X.num: just replaced 100 with 3
          x.num = null; // prints X.num: just replaced 3 with null

          以上示例代碼中,“oldValue”和“newValue”是兩個變量,它們分別表示對被替換成員的舊值和替換后的新值的引用(你可以按照自己喜好命名)。變量的上下文索引(由indexof操作符返回)與被替換成員的順序位置一致。

          top

          增量式求值和懶惰求值

          在JavaFX中,屬性初始化程序能夠使用bind操作符進行懶惰、增量式求值。使用bind初始化的屬性類似于包含公式的電子表格中的單元格。在包含此屬性的對象的生命周期中,只要在初始化表達式右側引用的任何對象發生改變,其左側的對象屬性將被自動更新。示例如下:

           	import java.lang.System;

          class X {
          attribute a: Number;
          attribute b: Number;
          attribute c: Number;
          }

          trigger on X.b = newValue {
          System.out.println("X.b is now {newValue}");
          }

          trigger on X.c = newValue {
          System.out.println("X.c is now {newValue}");
          }

          var x1 = X {
          a: 1
          b: 2 // X.b is now 2 is printed
          c: 3 // X.c is now 3 is printed
          };

          var x2 = X {
          a: x1.a // eager, non-incremental
          b: bind x1.b // eager, incremental (X.b is now 2 is printed)
          c: bind lazy x1.c // lazy, incremental (nothing is printed yet)
          };

          System.out.println(x2.a); // prints 1
          System.out.println(x2.b); // prints 2
          System.out.println(x2.c); // prints X.c is now 3, then prints 3

          x1.a = 5;
          x1.b = 5; // prints X.b is now 5, twice
          x1.c = 5; // prints X.c is now 5, twice

          System.out.println(x2.a); // prints 1
          System.out.println(x2.b); // prints 5
          System.out.println(x2.c); // prints 5

          上例中,x2的屬性b和c被綁定到x1的屬性b和c。這意味著當x1的b或c屬性被更新時,x2的b或c屬性都會相應地被更新。在x2中的b、c屬性之間的不同是:前者的屬性值在其屬性初始化程序中被立即更新,而后者的綁定直到其值被訪問時才被求值。

          注意:函數體無需bind操作符便可被增量地求值,但操作體則做不到。在改變本地變量的操作中并不觸發增量式求值。增量式求值不能在操作體內執行,除了表達式明確地以bind作為前綴。

          然而,當你在一個增量式求值上下文中調用操作或者Java方法,此調用本身將被增量式求值。這意味著如果此調用變成了對操作或者Java方法的全新調用(由于此調用被增量式求值),那么它所用到的任何參數值將被使用并返回新值。

          譯者注:此處的新值是與不進行增量式求值相比。

          相反,在增量式求值上下文中調用函數,此函數只能被調用一次,而其求值結果也將被合并到調用求值樹中。

          增量式求值是JavaFX的主要特征,它使定義復雜的動態GUI聲明成為了可能。懶惰求值的特性常用在處理像tree或者graph這樣的遞歸數據結構上。

          top

          反射

          JavaFX類、屬性、操作可以通過如下方式反射:

          	public class Class {
          public attribute Name: String;
          public attribute Documentation:String?;
          public attribute Superclasses: Class* inverse Class.Subclasses;
          public attribute Subclasses: Class* inverse Class.Superclasses;
          public attribute Attributes: Attribute* inverse Attribute.Scope;
          public attribute Operations: Operation* inverse Operation.Target;
          public function instantiate();
          }

          public class Operation extends Class {
          public attribute Target: Class? inverse Class.Operations;
          }

          public class Attribute {
          public attribute Name: String;
          public attribute Documentation: String?;
          public attribute Scope: Class? inverse Class.Attributes;
          public attribute Type: Class?;
          public attribute Inverse: Attribute* inverse Attribute.Inverse;
          public attribute OneToOne: Boolean;
          public attribute ManyToOne: Boolean;
          public attribute OneToMany: Boolean;
          public attribute ManyToMany: Boolean;
          public attribute Optional: Boolean;
          }

          JavaFX支持通過class操作符對類、屬性、成員函數和操作的進行反射訪問:

          	import java.lang.System;

          System.out.println(1.class.Name) // prints "Number"
          System.out.println("Hello".class.Name); // prints "String"

          class X {
          attribute a: Number;
          }
          var x = new X();
          System.out.println(x.class.Name); // prints "X"
          System.out.println(sizeof x.class.Attributes); // prints 1
          System.out.println(x.class.Attributes[0].Name); // prints "a"

          對屬性值進行反射訪問時,如果訪問操作數是屬性,則使用[]操作符:

          	import java.lang.System;

          class X {
          attribute a: Number;
          }
          var x = new X();
          x.a = 2;
          System.out.println(x[x.class.Attributes[Name == 'a']]); // prints 2
          // the above statement is equivalent to this non-reflective code:
          System.out.println(x.a);

          在JavaFX中,類的成員函數和操作本身被模式化作為在目標類中的類,而形參和返回值被表示為屬性。代表目標對象的屬性名是“this”。代表返回值的屬性名為“return”。代表形參的屬性具有和形參相同的屬性名。

          譯者注:這里的目標類是指使用成員函數和操作的類。而目標對象則指使用成員函數和操作的對象。

          從上例中可以發現,你也可以從Class對象中獲取相同的、被反射的操作。

          被反射的操作能夠像函數那樣通過將目標對象作為第一個參數、其它參數作為后面的參數的方式被調用:

          	import java.lang.System;

          class X {
          operation foo(n: Number): Number;
          }

          var x = new X();
          var op = x.class.Operations[Name == 'foo'];
          System.out.println(op(x, 100));

          // the above code is equivalent to the following non-reflective code:
          System.out.println(x.foo(100));

          bean屬性和Java類的公共字段被反射為JavaFX屬性。但是,Java方法不能被反射為JavaFX操作。如果你想調用某個Java方法,那么你可以通過簡單地使用Java API來實現。

          注意:與Java不同的:在JavaFX中class操作符被用于表達式,而不是用于類型名(type name)。因此作為補充,JavaFX支持從類型名中獲取反射類對象的語法:

          	:TypeName
          

          For example:

          	import java.lang.System;
          System.out.println(:System.Name); // prints "java.lang.System"
          System.out.println(:System.class.Name); // prints "Class"

          top

          廣度(Extents)和枚舉

          類的“廣度”,即此類的所有實例的集合,能夠通過以下語法獲得:

          	*:ClassName
          

          例如,下面的代碼打印出String類的所有實例:

          	import java.lang.System;

          for (i in *:String) {
          System.out.println(i);
          }
          注意:這是可選特性,默認情況下是失效的。 JavaFX也提供了聲明類的命名實例的能力:
          	objectName:ClassName
          

          例如:

          	import java.lang.System;

          myString:String = "This is a string";

          System.out.println(myString:String);

          這樣的命名實例是全局可訪問的,但通常必須使用類名進行限制。然而,在屬性初始化程序和賦值的上下文中,表達式類型的命名實例被引入到了詞法作用域 (lexical scope)(可見性弱于變量和屬性),并可以通過使用它們的無限定名(unqualified names)引用這些命名實例:

          	Button {
          mnemonic: P
          text: "Press Me"
          }

          在上面實例中,由于Buttonmnemonic屬性是KeyStroke類型的,因此我能夠通過使用它的無限定名訪問其命名值P,而在別處我將不得不使用P:KeyStroke來引用它。

          JavaFX使用與Java1.5同樣的語法來訪問枚舉類型值:

          	import java.lang.management.MemoryType;

          var heap = HEAP:MemoryType;
          var nonHeap = NON_HEAP:MemoryType;

          top

          相關資源

          top




          凡是有該標志的文章,都是該blog博主Caoer(草兒)原創,凡是索引、收藏
          、轉載請注明來處和原文作者。非常感謝。

          posted on 2007-08-17 00:39 草兒 閱讀(2537) 評論(3)  編輯  收藏 所屬分類: java 、JAVA WEB應用

          Feedback

          # re: JavaFX編程語言基礎 2007-08-19 00:01 ARPENKER
          草兒萬歲.  回復  更多評論
            

          # re: JavaFX編程語言基礎 2007-08-19 11:03 草兒
          哈哈 不要嚇我 我可不喜歡做皇上  回復  更多評論
            

          # re: JavaFX編程語言基礎[未登錄] 2007-12-27 14:33 eric
          語法不難,可看完還是沒搞懂函數編程的優勢在哪里  回復  更多評論
            

          主站蜘蛛池模板: 舒兰市| 伊春市| 景东| 靖西县| 禹城市| 台安县| 右玉县| 越西县| 阿克| 丹棱县| 兴化市| 遂平县| 廊坊市| 夏津县| 辰溪县| 平远县| 祁连县| 彩票| 社会| 台湾省| 江阴市| 黎川县| 金湖县| 特克斯县| 皮山县| 梓潼县| 万年县| 垣曲县| 双江| 延津县| 望都县| 玛纳斯县| 祁阳县| 水城县| 科技| 开原市| 革吉县| 延边| 泗阳县| 东阿县| 桂平市|