【问题标题】:Custom array wrapper class casting safety/efficiency自定义数组包装类强制转换安全/效率
【发布时间】:2016-12-29 23:14:37
【问题描述】:

我正在编写一个需要通用列表的 java 应用程序。这个列表需要能够经常动态地调整大小,显而易见的答案是通用的Linkedlist。不幸的是,它还需要像通过调用索引添加/删除它们一样频繁地获取/设置值。 Arraylist 可以很好地解决这个问题。由于这两个选项都不是我想要的,所以我创建了自己的通用数组包装类。我已经知道在 java 中创建泛型数组是非法的,并且我已经阅读过,通常不是使用泛型来定义数组的类型,而是创建一个 object[] 数组,然后强制转换每个元素单独到正确的类型。这类似于Arraylist 已经做的事情;但是,我已经读过强制转换在 java 中是一项非常昂贵的操作。因此,为了避免强制转换的必要性,我的自定义包装类看起来像这样。

public abstract class CustomArrayWrapper<E extends Object>{
    private E[] content;

    public abstract E[] empty(int n);

    public CustomArrayWrapper(){
        this.content = empty(0);
    }

    public CustomArrayWrapper(int n){
        this.content = empty(n);
    }

    public CustomArrayWrapper(E[] content){
        this.content = content;
    }

    public E[] content(){
        return content;
    }
}

这只是该类的基本内容,但主要思想是数组包装器的每个特定用途都扩展了 empty(int n) 方法,返回一个大小为 n 的数组,类型为 E,希望避免所有那个昂贵的铸件。使用String作为类型的示例如下。

public class StringArrayWrapper extends CustomArrayWrapper<String>{

    public StringArrayWrapper(){
        super();
    }

    public StringArrayWrapper(int n){
        super(n);
    }

    public StringArrayWrapper(String[] content){
        super(content);
    }

    public String[] empty(int n){
        return new String[n];
    }
}

我知道这个实现有效,我不知道的是

  1. 这样实施安全吗?
  2. 我知道转换有点挑剔,因为 Java 中内置了很多隐式转换,这实际上是一种绕过 Arraylist 已经执行的所有转换的方法吗?
  3. 是否比将每个元素转换为正确的类型(如ArrayList)效率更高/更低?

【问题讨论】:

  • “我已经读到在 Java 中强制转换是一项非常昂贵的操作”——真的吗?你有数字支持吗?
  • @sisyphus 有一些开销,请参阅stackoverflow.com/questions/2170872/…
  • 并不是说这完全回答了问题,但是您可以消除子类中的所有方法声明,除了empty 的具体实现。你需要访问数据数组而不是对数组索引使用额外的 getter 方法,并且担心显式转换的成本实际上会成为问题?
  • @lexicore 当然,但是一切都有一些开销。问题的前提是ArrayListLinkedList 性能不够好,而且选角“太贵了”。在创建自定义 Collection 实现之前,值得调查这些前提。
  • @sisyphus "但是一切都有*一些开销"* - 这绝对不是真的,不是所有的东西都有开销。

标签: java arrays generics casting


【解决方案1】:

检查unrolled linked list,这可能是您需要的。

接下来,您可能需要考虑通过扩展AbstractList 来实际实现List 以与集合框架保持一致。 “数组包装器”最终会很麻烦。

接下来,强制转换可能会有一些开销(请参阅Does Java casting introduce overhead? Why?),但我认为这不值得考虑。您的方法的缺点是您需要在每次使用时实施 empty 方法。从我的角度来看,对于可疑的性能改进来说,这个价格太高了。

回答您的问题:

  • 创建在子类中实现的数组模板方法是可以的。不太安全的是,您在 content 方法中公开此数组。
  • 我认为您无法摆脱强制转换。我也不认为选角表现值得担心。
  • 运行基准测试并对其进行测量。我认为它会更高效一些,因为不需要类型检查,但这不会是重要/引人注目的事情。

【讨论】:

    【解决方案2】:

    我建议您不要花费精力和时间尝试创建自定义集合类型,因为标准 Java API 已经有很多。您将赢得时间,并确保它安全且功能齐全。
    例如,如果您确实需要经常调整大小并经常获取和设置项目,我会选择其中一些:

    1- 如果您需要比调整大小更直接的访问:绝对选择 ArrayList。
    2- 如果您需要比直接访问更多的调整:您可以使用 LinkedList。

    我会尝试使用 HashMap,因为它是一个尝试优化直接访问和调整大小的集合,因此可能是您的最佳选择。唯一的区别是您必须使用键而不是索引来访问集合中的值,但您仍然可以像使用数组中的 int 索引一样使用 Integer 键。好处是您也可以使用任何类型的对象作为键。

    此外,您可以使用 LinkedHashMap,因为如果您需要,它会更快地遍历整个集合。

    无论如何,我不能向您保证这些是最适合您使用的选项,但我可以向您保证,您会找到合适的(已开发的)集合类型以在 Java API 中使用。

    这就是为什么我建议你阅读关于集合的官方文档,你会对它们有一个大致的了解,并能够为你的特定问题选择最有效的 --> https://www.tutorialspoint.com/java/java_collections.htm

    【讨论】:

    • +1 表示不尝试构建自定义集合类。相反,使用现有的类来衡量性能。
    • LinkedList 比 ArrayList 慢,在几乎不切实际的情况下。 JDK 人员甚至考虑弃用它。调整 ArrayList 的大小很快。遍历链表很慢。当您需要的是一个列表(即一个有序的、可迭代的集合)时,使用 HashMap 而不是 ArrayList 根本不是一个好建议。
    猜你喜欢
    • 2015-05-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多