3

这个34:00 的演讲描述了StructuredArrayJava 的 s 设计。一切都很清楚,除了事情:

它不应该是可构造的,即实例可能只能通过一些静态工厂方法(如newInstance )获得。同时,它们应该是可子类化的,这意味着必须有一个公共的构造函数,并且在运行时保证不可构造性。这听起来很hacky,所以我想知道为什么?

我知道工厂的一般优势,特别是静态工厂方法的优势。但是我们在这里得到了什么,所以它使黑客可以接受?

4

2 回答 2

3

该类的重点StructuredArray在于,有一天它可以被一个内部实现替换,该实现将整个数组(包括组件对象)分配为一个长内存块。 发生这种情况时,对象的大小将取决于元素的数量和元素类

如果StructuredArray有一个公共构造函数,那么你可以编写x = new StructuredArray<>(StructuredArray.class, MyElement.class, length). 这似乎没有任何问题,除了在bytecode中,这变成了new分配对象的指令,然后是调用对象构造函数的单独指令。 invokespecial

你看到了问题——new指令必须分配对象,但它不能,因为对象的大小取决于它没有的构造函数参数(元素类和长度)!直到稍后的构造函数调用才会传递这些。

有很多方法可以解决这样的问题,但它们都有点恶心。将构造封装在静态工厂方法中更有意义,因为这样您就无法编写 new StructuredArray...,并且 JVM 不必使用任何“魔术”来计算要在new指令中分配多少内存StructuredArray,因为不可能有任何这样的指示*。

如果后来的 JVM 想要提供分配连续数组的静态工厂的内在实现,那没问题——它在工厂方法调用中获得了它需要的所有信息。

NB* - 是的,好的,从技术上讲你可以new StructuredArray...,但它对你没有用处。

于 2016-07-22T01:47:13.263 回答
2

语义浏览 API 文档,我的理解是,这主要是语义的问题。并提供 Fluent API。此外,如果您查看演示文稿的结论幻灯片,您应该注意到语义项目符号位于第一位(如果我们不计算源代码 url)。

如果我们选择普通数组。它们呈现出清晰的语义:

  • 数组类型
  • 数组的长度
  • 元素的类型

因此

我们有一个使用数组的统一模型。API 非常清晰。没有 10 种不同的方式来处理数组。我相信对于 Java 语言开发者来说,这种 api 的清洁度是极其重要的。强迫不可构造性,他们隐含地强迫我们以他们希望我们使用它的方式使用 API。

建造

由于 StructuredArray 本质上也是数组。提出一个构造函数将立即迫使我们使用 StructuredArray 的具体实现,这会自动产生问题,引入这个“究竟是什么是“数组?”的统一模型。

这就是为什么通过 Javadoc 我们可以看到 StructuredArray 的实际构造方式:

  static <S extends StructuredArray<T>,T> S newInstance(java.lang.invoke.MethodHandles.Lookup lookup,
 java.lang.Class<S> arrayClass, 
 java.lang.Class<T> elementClass, 
 java.util.Collection<T> sourceCollection)

这里可见的是 StructuredArray 正在强制执行几件事:

  1. 它迫使所有客户端类使用“StructuredArray”而不是具体实现。
  2. StructuredArray 本质上是不可变的。
  3. 不变性意味着有一个严格的长度表示法。
  4. 结构化数组具有元素来源。一旦被消耗,可能会被丢弃。
  5. 与常规数组类似,结构化数组具有元素类型的概念。

我相信有一个非常强大的语义符号,而且作者也给了我们一个很好的提示,告诉我们编码应该如何发生。

结构化数组的另一个有趣特性是能够传递构造函数。我们再次谈论的是接口和 API 与实际实现的强解耦。

阵列模型

通过检查StructuredArrayModel http://objectlayout.github.io/ObjectLayout/JavaDoc/index.html?org/ObjectLayout/StructuredArray.html,我的话得到了进一步证实

StructuredArrayModel(java.lang.Class<S> arrayClass, java.lang.Class<T> elementClass, long length)

从构造函数中可以看到三件事: - 数组类 - 元素的类型 - 长度

进一步观察结构化数组支持的结构:

An array of structs: 
struct foo[];

A struct with a struct inside: 
struct foo { int a; bar b; int c; };

A struct with an array at the end: 
struct foo { int len; char[] payload; };

StructuredArrayModel完全支持它 与StructuredArray 相比,我们能够轻松地实例化模型的具体实现。

StructuredArray 向我们展示了传递伪构造函数的能力http://objectlayout.github.io/ObjectLayout/JavaDoc/org/ObjectLayout/CtorAndArgs.html

newInstance(CtorAndArgs<S> arrayCtorAndArgs, java.lang.Class<T> elementClass, long length)
于 2016-07-21T20:49:02.407 回答