【发布时间】:2008-11-11 05:36:11
【问题描述】:
我经常听到有人使用这个词,但我从来没有真正理解过。
这是什么意思,任何人都可以举一些例子/指向一些链接吗?
编辑:感谢大家的回复。你能告诉我规范表示如何在 equals() 性能中发挥作用,如 Effective Java 中所述吗?
【问题讨论】:
标签: java
我经常听到有人使用这个词,但我从来没有真正理解过。
这是什么意思,任何人都可以举一些例子/指向一些链接吗?
编辑:感谢大家的回复。你能告诉我规范表示如何在 equals() 性能中发挥作用,如 Effective Java 中所述吗?
【问题讨论】:
标签: java
我相信规范有两种相关用途:形式和实例。
规范形式意味着可以以多种方式描述或表示特定类型资源的值,并且选择其中一种方式作为首选规范形式。 (这种形式是规范化的,就像将其纳入圣经的书籍一样,而其他形式则不是。)规范形式的一个典型例子是分层文件系统中的路径,其中单个文件可以以多种方式引用:
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() 会为该文本返回相同的规范字符串对象。如果您通过该规范化器传递所有字符串,您就会知道等效字符串实际上是相同的对象引用,即别名
Java 5.0+ 中的枚举类型强制特定枚举值的所有实例在 VM 中使用相同的规范实例,即使该值已被序列化和反序列化。这就是为什么如果Days 是枚举类型,您可以在java 中不受惩罚地使用if (day == Days.SUNDAY)。为您自己的课程这样做当然是可能的,但要小心。阅读 Josh Bloch 的 Effective Java 了解详细信息和建议。
【讨论】:
“规范”一词只是“标准”或“通常”的同义词。它没有任何特定于 Java 的含义。
【讨论】:
了解“规范形式/表示”的一个很好的例子是查看“布尔”的 XML 模式数据类型定义:
{true, false, 1, 0} 而{true, false} 之一
这实质上意味着
"true" 和 "1" 被映射到规范的 repr。 "true" 和"false" 和 "0" 被映射到规范的代表。 "false"
【讨论】:
维基百科指出Canonicalization这个词。
将具有多种可能表示形式的数据转换为“标准”规范表示的过程。这可以用来比较不同表示的等价性,计算不同数据结构的数量,通过消除重复计算来提高各种算法的效率,或者可以施加有意义的排序顺序。
Unicode 示例对我来说最有意义:
Unicode 标准中的可变长度编码,尤其是 UTF-8,对于最常见的字符有不止一种可能的编码。这使得字符串验证更加复杂,因为必须考虑每个字符串字符的每个可能的编码。不考虑所有字符编码的软件实现存在接受在应用程序设计中被认为无效的字符串的风险,这可能会导致错误或允许攻击。解决方案是允许对每个字符进行单一编码。然后,规范化是将每个字符串字符转换为其单一允许编码的过程。另一种方法是让软件确定一个字符串是否被规范化,如果不是,则拒绝它。在这种情况下,在客户端/服务器上下文中,规范化将是客户端的责任。
总之,一种标准的数据表示形式。然后,您可以从此表格转换为您可能需要的任何表示形式。
【讨论】:
规范形式意味着元素的自然唯一表示
【讨论】:
在不失一般性的情况下简化为最简单和最重要的形式
【讨论】:
记住它的一个简单方法是神学界使用“规范”的方式,规范真理是真正的真理,所以如果两个人找到它,他们就发现了相同的真理。与规范实例相同。如果你认为你找到了其中的两个(即a.equals(b)),那么你真的只有一个(即a == b)。因此,在规范对象的情况下,平等意味着同一性。
现在进行比较。您现在可以选择使用a==b 或 a.equals(b),因为它们会在规范实例的情况下产生相同的答案,但 a==b 是参考的比较(JVM 可以比较两个数字的速度非常快,因为它们只是两个 32 位模式,而 a.equals(b) 是一个方法调用,需要更多开销。
【讨论】:
另一个很好的例子可能是:你有一个类支持使用笛卡尔坐标(x, y, z),球坐标(r, theta, phi)和柱坐标(r, phi, z)。为了建立相等性(equals 方法),您可能希望将所有表示转换为您选择的一种“规范”表示,例如球坐标。 (或者,也许您通常希望这样做 - 即使用一种内部表示。)我不是专家,但这确实是一个很好的具体例子。
【讨论】:
规范表示意味着以不同的风格查看字符 例如,如果我写一个字母 A 意味着另一个人可能会以不同的风格写字母 A:)
这是根据光学字符识别领域
【讨论】:
OP 关于规范形式的问题以及它如何提高equals 方法的性能都可以通过扩展Effective 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 的equalsIgnoreCase 方法增加了成本。如文所述
您可能希望存储该字段的规范形式,以便等于 方法可以对规范形式进行廉价的精确比较,而不是 成本更高的非标准比较。
Joshua Bloch 说规范形式是什么意思?嗯,我觉得多纳尔简洁的answer 很合适。我们可以以标准的方式将底层的String 字段存储在CaseInsensitiveString 示例中,也许是String 的大写形式。现在,您可以引用CaseInsensitiveString(其大写变体)的这种规范形式,并在您的equals 和hashcode 方法中执行廉价的评估。
【讨论】:
RDBMS 中的规范数据、图形数据;
将其视为 RDBMS 中数据的“规范化”或“规范形式”。相同的数据存在于不同的表中,用唯一标识符表示并映射到不同的表中。
或
想象一下图形数据库中以许多三元组表示的单一形式的数据。
它的主要好处是使 Dml(数据操作)更加高效,因为您可以只更新(插入/更新)一个值而不是多个值。
【讨论】: