我经常听到这个术语被使用,但我从来没有真正理解它。
这是什么意思,任何人都可以举一些例子/指点我的链接吗?
编辑:感谢大家的回复。你能否告诉我规范表示在equals()性能中是如何有用的,如Effective Java中所述?
答案 0 :(得分:59)
我认为规范有两种相关用途:形式和实例。
规范形式意味着可以用多种方式描述或表示特定类型资源的值,并选择其中一种方式作为受欢迎的规范形式。 (那个形式是 canonized ,就像把它变成圣经的书,而其他形式则没有。)规范形式的典型例子是分层文件系统中的路径,其中单个文件可以可以通过多种方式参考:
myFile.txt # in current working dir
../conf/myFile.txt # relative to the CWD
/apps/tomcat/conf/myFile.txt # absolute path using symbolic links
/u1/local/apps/tomcat-5.5.1/conf/myFile.txt # absolute path with no symlinks
该文件的规范表示的经典定义将是最后一条路径。使用本地或相对路径,如果没有上下文信息,则无法全局标识资源。使用绝对路径,您可以识别资源,但无法判断两条路径是否指向同一实体。将两个或多个路径转换为规范形式后,您可以执行以上所有操作,并确定两个资源是否相同,如果这对您的应用程序很重要(解决别名问题)。
请注意,资源的规范形式本身并不是特定形式的质量;对于给定类型(如文件路径),可以存在多种可能的规范形式(例如,按字典顺序首先列出所有可能的绝对路径)。一种形式被选为特定应用原因的规范形式,或者可以任意选择,以便每个人都说同一种语言。
将对象强制转换为规范实例是基本相同的想法,但不是确定资源的一个“最佳”表示,而是任意选择具有相同“内容”的一类实例的一个实例“作为规范引用,然后将所有引用转换为等效对象以使用一个规范实例。
这可以用作优化时间和空间的技术。如果应用程序中有多个等效对象实例,那么通过强制将它们全部解析为特定值的单个规范实例,您可以消除除每个值之外的所有值,节省空间和可能的时间,因为您现在可以比较那些具有引用标识(==)而不是对象等价(equals()
方法)的值。
使用规范实例优化性能的典型示例是使用相同内容折叠字符串。在具有相同字符序列的两个字符串上调用String.intern()
可保证为该文本返回相同的规范String对象。如果您通过该规范化器传递所有字符串,则您知道等效字符串实际上是相同的对象引用,即别名
Java 5.0+中的枚举类型强制特定枚举值的所有实例在VM中使用相同的规范实例,即使该值已序列化和反序列化也是如此。这就是为什么如果if (day == Days.SUNDAY)
是枚举类型,你可以在java中使用Days
而不受惩罚。为你自己的课程做这个当然是可能的,但要小心。阅读Josh Bloch撰写的 Effective Java ,了解详情和建议。
答案 1 :(得分:52)
维基百科指向术语Canonicalization。
将具有多个可能表示的数据转换为“标准”规范表示的过程。这样做可以比较不同的等价表示,计算不同数据结构的数量,通过消除重复计算来提高各种算法的效率,或者可以强加有意义的排序顺序。
Unicode 示例对我来说最有意义:
Unicode标准中的可变长度编码,特别是UTF-8,对大多数常见字符具有多种可能的编码。这使得字符串验证更加复杂,因为必须考虑每个字符串字符的每个可能的编码。不考虑所有字符编码的软件实现存在接受在应用程序设计中被视为无效的字符串的风险,这可能导致错误或允许攻击。解决方案是允许每个字符进行单一编码。然后,规范化是将每个字符串字符转换为其允许的单个编码的过程。另一种方法是软件确定字符串是否规范化,如果不是则拒绝它。在这种情况下,在客户端/服务器上下文中,规范化将是客户端的责任。
总之,数据的标准表示形式。然后,您可以从此表单转换为您可能需要的任何表示形式。
答案 2 :(得分:26)
理解“规范形式/表示”的一个很好的例子是查看“boolean”的XML模式数据类型定义:
{true, false, 1, 0}
而{true, false}
这实质上意味着
"true"
和"1"
映射到规范的repr。 "true"
和"false"
和"0"
已映射到canoncial repr。 "false"
答案 3 :(得分:24)
“规范”一词只是“标准”或“通常”的同义词。它没有任何特定于Java的含义。
答案 4 :(得分:17)
简化为最简单,最重要的形式而不失一般性
答案 5 :(得分:4)
记住它的一个简单方法是在神学界使用“规范”的方式,规范真理是真实的事实,所以如果两个人发现它,他们就找到了同样的真理。与规范实例相同。如果您认为自己找到了其中两个(即a.equals(b)
),那么您实际上只有一个(即a == b
)。因此,在规范对象的情况下,平等意味着身份。
现在进行比较。您现在可以选择使用a==b
或 a.equals(b)
,因为在规范实例的情况下它们会产生相同的答案,但是== b是参考的比较( JVM可以非常快速地比较两个数字,因为它们只是两个32位模式,而a.equals(b)
是一个方法调用,并且涉及更多的开销。
答案 6 :(得分:2)
另一个很好的例子可能是:你有一个支持使用笛卡尔(x,y,z),球形(r,theta,phi)和圆柱坐标(r,phi,z)的类。为了建立相等(equals方法),您可能希望将所有表示转换为您选择的一个“规范”表示,例如:球坐标。 (或者你可能想要这样做一般 - 即使用一个内部表示。)我不是专家,但这确实发生在我身上,可能是一个很好的具体例子。
答案 7 :(得分:0)
规范表示意味着以不同的方式查看角色 例如,如果我写一封信A意味着另一个人可能会以不同的方式写字母A:)
这是根据OPTICAL CHARACTER RECOGNITION FIELD
答案 8 :(得分:0)
规范形式意味着元素的自然唯一表示
答案 9 :(得分:0)
OP有关规范形式及其如何提高equals
方法性能的问题都可以通过扩展有效Java中提供的示例来回答。
请考虑以下课程:
public final class CaseInsensitiveString {
private final String s;
public CaseInsensitiveString(String s) {
this.s = Objects.requireNonNull(s);
}
@Override
public boolean equals(Object o) {
return o instanceof CaseInsensitiveString && ((CaseInsensitiveString) o).s.equalsIgnoreCase(s);
}
}
此示例中的equals
方法通过使用String
的{{1}}方法增加了成本。如文字中所述
您可能想存储字段的规范形式,因此等于 方法可以对规范形式进行便宜的精确比较,而不是 更昂贵的非标准比较。
约书亚·布洛赫(Joshua Bloch)说规范形式是什么意思?好吧,我认为Dónal的简洁answer非常合适。我们可以以 standard 的方式存储equalsIgnoreCase
示例中的基础String
字段,也许是CaseInsensitiveString
的大写形式。现在,您可以引用String
的这种规范形式,它是大写的变体,并可以在您的CaseInsensitiveString
和equals
方法中执行廉价的评估。
答案 10 :(得分:0)
RDBMS中的规范数据,图形数据;
可以认为是RDBMS中数据的“规范化”或“规范形式”。相同的数据存在于不同的表中,用唯一的标识符表示,并将其映射到不同的表中。
或
想一想Graph数据库中以多种形式表示的数据的单一形式。
它的主要好处是使Dml(数据操作)更有效,因为您只能对一个值(而不是多个值)进行高位插入(插入/更新)。