Apache Commons OGNL语法说明_翻译

原文链接

http://commons.apache.org/proper/commons-ognl/language-guide.html

前言

  对象导航图语言 (Object Graph Navigation Language),简称OGNL。

  本人才疏学浅,对原文理解错误、翻译错乱之处,还请多多指出~

译文

1 语法

  基本的OGNL表达式非常简单。虽然该语言的特性已经非常丰富,但是你通常不用担心该语言更为复杂的部分,当然,对于简单的情形,就更不必担心了。比方说,要从当前对象中获取它的name属性,对应的OGNL表达式就是一个简单的name。而如果要从headline对象中获取text属性,则对应的OGNL表达式是headline.text

  什么是属性?大体来说,一个OGNL属性和一个bean对象的属性相同。意思是说一个属性有一对儿get/set方法,或者就只是一个字段(详细说起来比较复杂,因为不同的对象有不同的属性,后面我们细说)。

  OGNL表达式的基本组成元素就是导航链,通常简称为链。最简单的链由以下部分组成:

表达式的组成元素例子
属性名比如上面提到的nameheadline.text
方法调用使用hashCode()来获取一个对象的哈希值
数组下标使用listeners[0]来获取当前listeners数组的第一个元素

  所有OGNL表达式都从当前对象的上下文中取值,导航链只使用上一个链接的结果做为下一个链接的当前对象。你可以任意拓展链条的长度,如下面的例子所示:

name.toCharArray()[0].numericValue.toString()

  上面表达式的取值步骤是:

  • 用户通过OGNL上下文,提供给OGNL的初始对象(或者叫根对象),从中可以获取name属性;
  • 对上一步的结果,调用String类的toCharArray()方法;
  • 从上一步得到的数组中,取出第一个字符(因为下标是0);
  • 从上一步得到的字符中,获取它的numericValue属性(因为这个字符是用Character类表示的,此类有一个getNumericValue()方法,可以获取此属性);
  • 上一步的结果是一个Integer对象,本步使用toString()方法,最终把它转换为String对象。

  注意,上面的例子只能用来从一个对象中取值,而不能用来设置值。把上面的表达式传递给Ognl.setValue()方法,将会抛出InappropriateExpressionException(不合适的表达异常),这是因为此链的最后一个链接,既不是属性名,也不是数组下标,却是一个toString()方法。

  上面这些语法足以完成你要做的绝大多数工作。

2 表达式

  本节详述OGNL表达式的各种元素。

2.1 常量

  OGNL有下面几种常量(也可以说是字面量):

  • 字符串字面量,在Java中使用" "包围,包围在其中的"'需要使用转义,如\"\'
  • 字符字面量,在Java中使用' '包围,同样也可能会用到转义;
  • 数值字面量,比Java多一些种类。除了Java的int, long, float和double类型外,OGNL还允许你使用bB后缀来表示BigDecimal类型的数值,也允许使用hH后缀来表示BigInteger类型的数值。注意这里的h可以认为是取自huge,而不是取自 hexadecimal(16进制数字);
  • 布尔字面量,包含truefalse
  • null字面量

2.2 引用属性

  OGNL在处理属性引用时,针对不同的对象类型,采取不同的方式。
  比如,从Map集合对象中引用一个任意类型的属性(字符串类型 或 数值类型 等),就会以此属性名为key,返回此key对应的value。
  再比如,从List集合对象或数组对象中引用一个数值类型的属性时,就会以此属性为下标,返回对应的值。而从List集合对象或数组对象中引用一个字符串类型的属性时,就调用此属性的get/set方法等(和普通对象一样)。
  对于其它普通对象,它们只能处理字符串类型属性的引用,调用此属性的get/set(或者is/set)方法,或者直接调用这个字段(需要public访问权限)。

  注意这里的新术语。属性names可以是任何类型,而不仅仅是字符串。但是要引用非字符串属性,必须使用我们所说的 “索引” 符号。例如,要获取数组的长度,可以使用以下表达式:

array.length

  但是要获取数组中下标为0的元素,你就必需使用下面这样的表达式:

array[0]

  注意Java集合类有一些与之相关的特殊属性。

2.3 索引

  如上所述,虽然 “索引” 符号 是属性引用中的计算形式,但是效果等同于常量形式。

  比如,OGNL内部处理array.lenth表达式的方式和下面的表达式的一样:

array["length"]
/*
备注:array.length 就是所谓的常量形式
array["length"] 就是所谓的计算形式
这里感觉有些牵强 😂
*/

  而且,下面的表达式会得到相同的结果:

array["len"+"gth"]
2.3.1 数组 和 List集合的索引

  针对Java的数组和List集合的索引非常简单,就和Java本身的一样。给一个整数类型的下标,就可以获取到对应的元素。如果下标越界,就会抛出IndexOutOfBoundsException异常,这和Java一样。

2.3.2 JavaBeans的索引属性

  JavaBeans支持索引属性的概念。具体来说,这意味着一个对象有一组遵循以下模式的方法:

  • public PropertyType[] getPropertyName()
  • public void setPropertyName(PropertyType[] anArray)
  • public PropertyType getPropertyName(int index)
  • public void setPropertyName(int index, PropertyType value)

  OGNL可以理解这些,并且通过索引符号提供对属性的直接访问。例如:

someProperty[2]

  上面的例子会自动调用正确的索引属性访问器。在上例中,这个索引属性访问器就是getSomeProperty(2)setSomeProperty(2, value)。如果没有索引属性访问器,则会找到名为someProperty的属性,并对其应用索引。

2.3.3 OGNL的对象索引属性

  OGNL拓展了索引属性的概念,使得索引属性可以使用任何类型的对象,而不仅仅是整数。在2.3.2中JavaBeans索引属性只能是整数。当使用对象索引属性时,OGNL会寻找符合下面模式的方法:

  • public PropertyType getPropertyName(IndexType index)
  • public void setPropertyName(IndexType index, PropertyType value)

  在get和set方法中,PropertyTypeIndexType要一致。使用对象索引属性的活生生的例子,就是Servlet API —— Session类中attribute属性的get/set方法,如下所示:

public Object getAttribute(String name)
public void setAttribute(String name, Object value)

  下面的表达式可以获取或设置attribute属性:

session.attribute["foo"]

3 方法调用

  因为OGNL是解释执行的,它必须在运行时选择正确的方法,另外,除了提供的实际参数外,没有关于此参数的、额外的类型信息,所以OGNL的方法调用和Java的不太一样。OGNL总是选择它能找到的与所提供的参数类型相匹配的最合适的方法。如果有两个或以上与给定参数类型完全匹配的方法,OGNL则会随意选择一个来执行。

  特别地,null参数可以和任何非基本类型(也就是Java中的引用数据类型)相匹配,所以这比较容易导致方法调用错误。

  注意,方法的参数是用逗号分隔的。因此不能在参数列表中使用逗号来做其它用途,除非在圆括号中使用它。比如:

method( ensureLoaded(), name )

  会调用有2个参数的方法,然而:

method( (ensureLoaded(), name) )

  则会调用有1个参数的方法。

4 变量引用

  OGNL有一个简单的变量模式,它允许你存储中间结果并再次使用它们,或者只是给一个表达式重新命名,以使它更容易理解。OGNL的所有变量都是整个表达式的全局变量。你可以在变量名前使用#符号来引用它,如下所示:

#var

  OGNL也会把表达式计算过程中,各个节点的当前对象存储在this变量中,它可以像其它变量一样被引用。比如,下面的表达式操作着listeners集合的元素个数,如果它大于100,就把它乘以2,否则就给它加20。

listeners.size().(#this > 100? 2*#this : 20+#this)

  OGNL可以被一个定义了变量初始值的映射调用。调用OGNL的标准方法,定义了root变量(它保存着初始或根对象)以及context变量(它存储着变量所在的Map集合)。

  要显式地给一个变量赋值,只需在左边写一个变量引用赋值语句:

#var = 99

5 括号表达式

  如你所料,括号表达式是一个计算单元,与周围的操作符分开计算。使用括号表达式可以改变计算顺序。括号表达式也是在方法调用中使用逗号操作符的唯一方式。

6 链接子表达式

  如果你在点号后面使用括号表达式,那么当前对象会贯穿整个括号表达式的执行过程。如下面的例子:

headline.parent.(ensureLoaded(), name)

  整个计算过程是:先经过headlineparent属性,然后调用ensureLoaded()方法确保parent对象已经加载,接着返回(或设置)parentname属性。

  顶层表达式也可以使用这种方式链接。表达式的结果是它最右边的元素。

ensureLoaded(), name

  这会首先在根对象中调用ensureLoaded()方法,然后从根对象中获取name属性,做为表达式的返回值。

7 构建集合

7.1 List集合

  可以使用花括号括起来的一系列表达式来创建一个List集合。和方法调用一样,这些表达式不能使用逗号操作符,除非被圆括号括起来。比如下面的例子:

name in { null,"Untitled" }

  上面的例子会测试name属性是不是null或者等于Untitled

  上面描述的语法会创建一个List接口的实例,但具体的子类型没有指定。

7.2 本地数组类型

  有时你想创建Java本地的数组类型,比如int[]Integer[]。OGNL支持用通常的方式创建本地数组,支持在创建时初始化或者只给出数组的长度。

new int[] { 1, 2, 3 }

  上面的例子创建了一个int类型的数组,包含3个元素:1,2,3。

  可以给出数组的长度来创建一个全部是null0的数组。

new int[5]

  上面创建了一个int数组,长度为5,全部的元素都初始为0。

7.3 Map集合

  Map集合也可以使用特殊的语法来创建:

#{ "foo" : "foo value", "bar" : "bar value" }

  这会创建一个Map集合,有2个key,分别是"foo""bar"

  想要指明具体的Map类型的人士,可以在花括号前指明,如下所示:

#@java.util.LinkedHashMap@{ "foo" : "foo value", "bar" : "bar value" }

  上面的例子会创建一个LinkedHashMap类型的实例,它可以保证有序。

8 对集合使用投影

  OGNL提供了一种简单的方式来从集合中提取出每个元素中共有的属性或方法,我们把这种方法叫做“投影”,实际上“投影”是数据库的术语,意思是从表中选择列的子集。比如下面的例子:

listeners.{delegate}

  这会返回所有listeners的delegate属性。有关OGNL如何将各种对象做为集合处理的,请查看“强制”这一节。

  在投影过程中#this变量表示集合迭代的当前元素。

objects.{ #this instanceof String ? #this : #this.toString()}

  上面会创建一个新的集合,它的元素都是objects集合元素的字符串形式。

9 从集合中选择

  OGNL提供了一种简单的方式来从集合中选择一些元素,然后把结果保存到一个新的集合中。我们把这种方法叫做“选择”,实际上“选择”是数据库的术语,意思是从表中选择行的子集。比如下面的例子:

listeners.{? #this instanceof ActionListener}

  这会返回listeners集合中类型为ActionListener的元素的集合。

9.1 选择第一个匹配的

  为了获取匹配到的集合中第一个匹配的元素,你可以使用类似listeners.{? true}[0]的索引来实现。然而,这种方式比较笨,因为如果匹配没有结果(也就是返回的集合是空集),那么你就会收到ArrayIndexOutOfBoundsException异常。

  选择的语法也支持选择第一个匹配的元素,并以一个集合的形式返回。如果所有元素的都匹配没有成功,那么就会返回一个空集合。

objects.{^ #this instanceof String }

  上面的例子会返回objects集合的第一个String类型的元素。

9.2 选择最后一个匹配的

  与获取第一个匹配的类似,有时你会想获得最后一个匹配的元素。

objects.{$ #this instanceof String }

  这会返回objects集合的最后一个String类型的元素。

10 调用构造方法

  你可以在Java中,用new操作符创建一个对象,OGNL也可以这样做。但有一个不同是在OGNL中,你必须使用类的全限定名,除非你使用的类在java.lang包中(比如,应该使用new java.util.ArrayList(),而不是new ArrayList())。

  只有使用默认的类解析器时才会出现上面这种情况。通过自定义类解析器,可以抹除类全限定名的限制。具体可以参考OGNL开发者文档中有关ClassResolver类的介绍。

  OGNL会选择合适的构造方法,其原理就和在重载的方法中找到合适的一样。

11 调用静态方法

  你可以使用@class@method(args)的语法,来调用静态方法。如果不写class,那么默认的就是java.lang.Math,为的是让调用minmax等方法更方便一些。如果你要写class,那么请使用类的全限定名。

  如果你想调用类中的静态方法,也可以通过此类的对象来调用,就好像这个静态方法是一个实例方法一样。

  如果这个静态方法被重载了,OGNL会选择合适的静态方法,其原理就和在普通重载的方法中找到合适的一样。

12 调用静态变量

  你可以使用@class@field的语法,来调用静态变量。这个类必须全限定名。

13 表达式取值

  如果有一个OGNL表达式,记做A,A的后面有一个括号表达式B,而且B前面没有点,那么OGNL会把A的结果做为新的表达式,记为C,然后把B的结果做为根对象D,由D调用表达式C。直观一点表示就是:

A(B)
A的结果是C
(B)的结果是D
最终执行D.C
/*
这里 弯弯绕得厉害,原文真难懂 😂
*/

  表达式A的结果可以是任意对象(记为C),如果C是一个AST(抽象语法树),那么OGNL就假设C是一个表达式的解析形式,然后直接解解释C。否则,它就获取C的字符串值(记为E),把E解析为AST后,再解释它。

  例如:

#fact(30H)

  上例会查找fact变量,把fact变量的值解释为OGNL表达式,并被类型为BigInteger,值为30的对象调用。看后面 伪Lambda表达式 的例子可以明白,上例最终会计算出30的阶乘。需要注意的是,表达式求值和方法调用在语法上有歧义。OGNL处理的方式是能当方法调用,就当方法调用。比如说,当前对象有一个fact属性,它存储着OGNL求阶乘的表达式,你不能用下面的方式调用它来做表达式求值:

fact(30H)

  因为OGNL会把它当做fact方法调用,而不是当做表达式求值。解决办法是,你可以用圆括号把fact属性括起来,用以表示是要做表达式求值:

(fact)(30H)

14 伪Lambda表达式

  OGNL提供了简洁的Lambda表达式语法。Lambda表达式可以让你写一些简单的函数。但它不是真正意义上的Lambda表达式,因为这里没有闭包——在OGNL中,所有的变量都是全局的。

  比如,下例的OGNL表达式声明了一个递归实现求阶乘的函数,然后调用此函数:

#fact = :[#this<=1? 1 : #this*#fact(#this-1)], #fact(30H)

  方括号中的就是Lambda表达式。#this变量是函数的参数,它的初始值是30H,然后在每次的递归调用时都递减1。

  OGNL把Lambda表达式当做常量。Lambda表达式的值是AST(抽象语法树),AST就是表达式的解析形式。

15 集合的伪属性

  OGNL为集合提供了一些特殊的属性。这样做的原因是集合在方法命名方面不遵循JavaBeans的模式,因此需要调用size(), length()等方法,而不能直观地将它们当属性调用。OGNL改变了这一现状,它提供了一些内置的伪属性。

      集合的特殊伪属性

集合特殊的属性
Collection(被Map, List, Set继承)size:集合的长度;
isEmpty:判断集合是否为空
Listiterator:获取List的迭代器Iterator
Mapkeys:获取Map中所有key的Set集合
values:获取Map中所有value的Collection集合
注意 这些属性,加上sizeisEmpty,不同于map集合 索引形式的数据访问方式(例如,someMap["size"]会从集合中获取key等于"size"对应的值,然而someMap.size会获取map集合的长度)
Setiterator:获取Set的迭代器Iterator
Iteratornext:获取迭代的下一个元素
hasNext:判断迭代过程是否还有下一个元素
Enumerationnext:获取枚举迭代的下一个元素
hasNext:判断枚举迭代是否还有下一个元素
nextElementnext的同义词
hasMoreElementshasNext的同义词

16 一些与Java不同的操作符

  大多数OGNL的操作符都借鉴自Java,其效果与Java的也一样。可以看OGNL语法参考来获取更多信息。下面我们要说的是Java里没有,而OGNL有的操作符,以及与Java不同的OGNL操作符。

  • 逗号操作符(也叫顺序操作符)。这借鉴自C语言。逗号用于分隔两个完全独立的表达式。逗号表达式中第2个表达式的值,就是整个逗号表达式的返回值。例如:
ensureLoaded(), name

  当这个表达式被计算时,首先会调用ensureLoaded()方法(此方法的含义很可能是要确保当前对象的所有组成部分都已加载到内存),然后会取出name属性的值(如果是取值操作的话)或者替换name属性的值(如果是设值操作的话);

  • 你可以使用一对儿花括号声明一个List集合对象,如下:
{ null, true, false }
  • in操作符(not in是它的反义词)。这俩是用来做包含判断的,看一个值是否在集合中。比如:
name in {null,"Untitled"} || name

17 设值 vs 取值

  如前所述,一些值是可获取的,但不可设置。这是表达式本身的问题。比如:

names[0].location

  就是一个可以设置的表达式——这是由表达式的尾部是一个可设置的属性决定的。

  然而,有一些表达式,比如:

names[0].length + 1

  是不可设置的,因为表达式的尾部不能解析为一个对象的属性。它只是一个计算值。如果你想用Ognl.setValue()方法来计算此表达式,就会得到InappropriateExpressionException异常。

  也可以使用=和取值表达式来设置变量。这种做法在取值表达式需要设置一个变量作为执行副本的时候就会很有用。

18 类型的强制转换

  接下来,我们介绍OGNL如何把对象解析为多种类型。看下面的例子,就可以明白OGNL如何把对象转换为boolean, number, integercollection

18.1 把对象解析为布尔类型 Booleans

  在OGNL中,任何对象都可以当布尔类型来用。OGNL解析把对象解析为布尔类型的规则是:

  • 如果这个对象是Boolean类型,就直接返回;
  • 如果这个对象是Number类型,则将其双精度浮点值与0进行比较。非0为true,0是false
  • 如果这个对象是Character类型,它的字符值不是0的时候返回true,否则返回fasle
  • 其他的情况,只有对象不为null时返回true,否则返回false

18.2 把对象解析为数值类型 Numbers

  数学运算符会试图将操作数视为数字。基本数据类型的包装类(Integer, Double以及CharacterBoolean等,都会被视为整数)和java.math包下的“大”数值类型(BigIntegerBigDecimal),它们被认为是特殊的数字类型。对于其他类型的对象,OGNL会尝试把这些对象的字符串值转换为数值。

  对于有两个操作数的数学运算符,可以使用下面的规则来确定计算结果的类型。实际运算结果的类型可能要比下面给出的要宽:

  • 如果两个操作数是相同的类型,那么结果也是相同的类型(如果有返回结果的话);
  • 如果某个操作数不是数值类型,那么它会被当成Double来使用;
  • 如果两个操作数都是实数的近似值(Float, DoubleBigDecimal类型),那么结果的类型将是两个操作数的类型中更宽的那个;
  • 如果两个操作数都是整数类型(Boolean, Byte, Character, Short, Integer, Long或者BigInteger类型),那么结果的类型将是两个操作数的类型中更宽的那个;
  • 如果一个操作数是实数类型,而另一个是整数类型,那么若是这个整数的取值小于int的范围,结果的类型就是实数类型。若是这个整数的类型是BigInteger,那么结果的类型就是BigDecimal。其他的情况,结果的类型就是比那个实数类型的操作数更宽的类型,或者Double类型。

18.3 把对象解析为整数 Integers

  对于只作用于整数的操作符(比如位移运算符),会把它们的操作数当做数值。这数值的类型,除了原BigDecimalBigInteger类型会被当做BigInteger来处理外,其他的数值类型都会被当做Long

  对于操作数被当做BigInteger的情况,返回值仍然是BigInteger类型;对于操作数被当做Long的情况,返回值可以是与操作数一样的类型,或者合适的类型,若都不满足,则最终是Long类型。

18.4 把对象解析为集合 Collections

  集合的投影和选择操作符(例如:e1.{e2}e1.{?e2}),以及in操作符,都将其中一个操作数当做集合来遍历。针对不同类型的操作数,会有不同的情况:

  • Java数组从前到后遍历;
  • java.util.Collection接口的成员,使用迭代器来遍历;
  • java.util.Map接口的成员,使用迭代器来遍历集合的value;
  • java.util.Iteratorjava.util.Enumeration的元素通过迭代来遍历;
  • java.lang.Number的对象“遍历”时,会返回从0开始,到小于此数值的整数构成的一系列整数;
  • 所有其它对象,都会被视为只包含它们自己的,只有一个长度的集合。

19 附录:OGNL 语法参考

  本节将非常详细地述说OGNL的语法和实现。请参阅下面的OGNL完整操作符表、OGNL如何进行类型强制转换 和 OGNL基本表达式详述。

19.1 操作符

  OGNL借鉴了大多数Java操作符,并添加了一些新操作符。在大多数情况下,OGNL处理给定操作符的方式与Java相同,但需要注意的是,OGNL本质上是一种无类型的语言。这意味着OGNL中的每个值都是一个Java对象,OGNL会把每个对象强制转换为适合其使用情况的类型(请参阅18 类型强制转换 一节)。

  下表OGNL操作符的顺序,是按优先级由低到高排列的。当同一个单元格中有多个操作符时,表示这些操作符具有相同的优先级,在表达式中同时出现时,会按从左到右的顺序计算。

操作符整个表达式被取值时整个表达式被设值时
e1, e2
顺序操作符(也叫逗号表达式)
e1e2使用相同的源对象进行计算,并返回e2的计算结果会对e1进行取值,然后对e2进行设值
e1 = e2
赋值操作符
会对e2进行取值,对e1进行设值(设置的就是e2的值)不能对整个表达式设值
e1 ? e2 : e3
三目操作符
e1进行取值,并把它转化为布尔类型,然后依据它为truefalse来对e2e3进行取值e1进行取值,对e2e3进行设值
e1 || e2 或者写成 e1 or e2
逻辑或操作符
e1取值,如果值为true,就返回true,否则才取e2的值。简单地说,就是短路或e1的值为false时,对e2设值。否则不进行设置
e1 && e2或者写成e1 and e2
逻辑与操作符
e1取值,如果值为false,就直接返回false。否则才取e2的值。简单地说,就是短路与e1的值为true时,对e2设值。否则不进行设值
e1 | e2或者写成e1 bor e2
按位或操作符
e1e2会解析换为整数,计算结果也是一个整数不能对整个表达式设值
e1 ^ e2或者写成e1 xor e2
按位异或操作符
e1e2会被解析为整数,计算结果也是一个整数不能对整个表达式设值
e1 & e2或者写成e1 band e2
按位与操作符
e1e2会被解析为整数,计算结果也是一个整数不能对整个表达式设值
e1 == e2或者写成e1 eq e2
等于操作符
e1 != e2或者写成e1 neq e2
不等于操作符
把它当成Java中的equals()方法就好不能对整个表达式设值
e1 < e2或者写成e1 lt e2
e1 <= e2或者写成e1 lte e2
e1 > e2或者写成e1 gt e2
e1 >= e2或者写成e1 gte e2
e1 in e2
e1 not in e2
 如果这些操作符的操作数不是数值类型,而且实现了Comparable接口,那么就使用compareTo()方法来比较。其它情况,OGNL就会把操作数解析为数值,进行数值比较。
in操作符不是Java自带的,它会判断集合e2中是否包含元素e1。in操作符效率不高,它会遍历集合,并使用标准的OGNL等值判断
不能对整个表达式设值
e1 << e2或者写成e1 shl e2
按位左移操作符
e1 >> e2或者写成e1 shr e2
按位右移操作符
e1 >>> e2或者写成e1 ushr e2
逻辑右移操作符
e1e2会被解析为整数,计算结果也是一个整数不能对整个表达式设值
e1 + e2
e1 - e2
相加操作符会做字符串拼接,或者数值相加;相减操作符只能作用于数值不能对整个表达式设值
e1 * e2
e1 / e2
e1 % e2
乘、除会把操作数解析为数值类型,取余会把它的操作数解析为整数类型不能对整个表达式设值
+ e
一元加操作符
- e
一元减操作符
! e或者not e
逻辑非
~ e
按位非
e instanceof class
判断是否为子类
 一元加操作符,如果操作数是数值类型,那么就返回它本身;如果操作数是字符串类型,那么就把它转换为数值。
 一元减操作符,如果操作数是数值类型,那么就对它求负;如果操作数是字符串类型,那么就把它转换为数值,并求负。
 按位非不会把操作数解析为整数。
不能对整个表达式设值
e.method(args) 方法调用
e.property 取属性
e1[e2] 索引
e1.{e2} 投影
e1.{? e2} 选择
e1.(e2) 链接子表达式
e1(e2) 表达式求值
总的来说,导航链从左到右一个一个地计算这些操作符中,只有一部分可以对整体设值。只有链尾是属性调用(e.property),或者是索引(e1[e2]),再或者是子表达式(e1.(e2)),另外取值表达式也可以。
constant 常量
( e ) 逗号表达式
method(args) 方法调用
property 属性调用
[ e ] 索引
{ e, ... } 创建List集合
#variable 上下文变量引用
@class@method(args) 静态方法调用
@class@field 静态字段调用
new class(args) 构造方法调用
new array-component-class[]{ e, ... } 创建数组
#{ e1 : e2, ...} 创建Map集合
#@classname@{ e1 : e2, ...} 使用具体的Map类型创建集合
:[ e ] Lambda表达式
基本表达式 只有属性调用,索引调用或者 上下文变量调用 可以对整体设值。
 其中,索引调用 [ e ],会先计算e的值,然后做为当前对象要设值的属性名(可以是字符串类型,或者其他任何类型)。
 剩下的 上下文变量 和 属性调用的设值就更直接了。
  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Apache Commons Codec 1.4是Apache软件基金会下的一个开源项目,它提供了一组编解码器用于处理各种编码和解码的需求。Apache Commons Codec 1.4提供了许多常见编码和解码算法的实现,如Base64、Hex、URL、Soundex等。 在编码和解码中,Base64是最常用的一种算法之一。Apache Commons Codec 1.4提供了Base64的实现,它可以将二进制数据转换为文本格式,以方便传输和存储。与此同时,Apache Commons Codec 1.4还提供了Base64的解码方法,可以将Base64格式的文本转换为原始的二进制数据。 除了Base64,Apache Commons Codec 1.4还提供了Hex编码和解码的功能。Hex可以将二进制数据按照16进制的方式表示,方便人们查看和理解。Apache Commons Codec 1.4提供了将二进制数据转换为Hex格式的编码方法,以及将Hex格式的文本转换为二进制数据的解码方法。 在网络传输和URL处理中,URL编码是一个很常见的需求。Apache Commons Codec 1.4提供了URL编码和解码的功能,可以将URL中的特殊字符进行编码,以保证数据的安全性和正确性。 此外,Apache Commons Codec 1.4还提供了Soundex算法的实现,它可以将英文单词进行音标化的编码。这在文本搜索和相似度匹配中可以发挥作用。 总而言之,Apache Commons Codec 1.4是一个功能强大、易于使用的开源编解码库,提供了多种编解码算法的实现,为我们在编码和解码的过程中提供了很大的便利。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值