如果你发现在一个接口使用有如下定义方法:

1
public String[] getParameters();

  那么你应该认真反思。数组不仅仅老式,而且我们有合理的理由避免暴露它们。在这篇文章中,我将试图总结在Java API中使用数组的缺陷。首先从最出人意料的一个例子开始。

  数组导致性能不佳

  你可能认为使用数组是最快速的,因为数组是大多数collection实现的底层数据结构。使用一个纯数组怎么会比使用一个包含数组的对象性能更低?

  让我们先从这个看起来很熟悉的普遍的习惯用法开始:

1
2
3
public String[] getNames() {
  return namesList.toArray( new String[ namesList.size() ] );
}

  这个方法从一个用来在其内部保存数据的可变集合处创建了一个数据. 它通过提供一个确切大小的数组来尝试优化数组的创建. 有趣的是,这一“优化”使得其比下面的更简单的版本速度还要慢(请看图表中绿色VS橘色条):

1
2
3
public String[] getNames() {
  return namesList.toArray( new String[ 0 ] );
}

  不过,如果方法返回的是一个List, 创建防御式的副本又更加的快了 (红条):

1
2
3
public List<String> getNames() {
  return new ArrayList( namesList );
}

  不同之处在于一个ArrayList将它的数据项放在一个Object[]数组中,并且使用的是无类型的toArray方法,其比有类型的方法要快很多(蓝条). 这是类型安全的,因为无类型的数组时封装在由编译器检查的泛型类型ArrayList<T>中的.

  这个图标展示了一个在Java 7上n=5的参考标准. 不过,更多的数据项或者是另外一个VM情况系啊,这幅图片并不会改变太多. CPU的开销可能并不会太剧烈,但是会有增长. 机会有一个数组的使用者应该将其转换到一个集合中去,以便利用它做任何事情, 然后将结果转换回一个数组,来送进另外一个接口的方法中,诸如此类做法.

  使用一个简单的数组列表,而不是可以提高性能的一个数组,无需过多的奔波。数组列表对包装数组增加了一个持续的32字节开销。例如,十个对象的一个数组,需要104个字节,一个数组列表有136字节。使用集合,你甚至可以决定返回内部列表一个不可修改的版本:

1
2
3
public list<string>getnames()
    return collections.unmodifiablelist(namelist);
}

  在常数时间内完成这个操作,因此它比任何上述(黄色条)要快很多。这与备用副本不一样。当你的内部数据库变更时,可以改变一个不可修改的集合。如果发生这种情况,客户可以运行ConcurrentModificationException.当迭代此项目时,它可能被认为是一个在运行时,接口提供了一个抛出Unsupportoperationexception的方法的不友好界面。不过,至少会在内部使用,这个方法对于一个备用副本来说,可能是一个高性能的解决方案-使用数组,这是不可能的

  数组定义一个结构,而不是一个接口

  Java 是一门面向对象的语言。面向对象的核心概念就是提供一些方法来访问和操作它们的数据,而不是直接对数据域进行操作. 这些方法创建一个接口来描述你可以在对象上面做的事情.

  由于java已经对性能做了设计,原生类型和数组已经被融合进了类型系统之中. 对象可以使用数组来在内容高效地存储数据. 然而,即使通过数组来呈现一个可变集合的元素,它们也不会提供任何方法来访问和操作这些元素. 事实上,除了直接访问的替换元素之外,在数组上你没有多少其它事情可以做. 数组甚至连toString 和 equals 都没有一个有意义的实现, 而集合却有:

1
2
3
4
5
6
7
8
9
10
11
12
String[] array = { "foo""bar" };
List<String> list = Arrays.asList( array );
  
System.out.println( list );
// -> [foo, bar]
System.out.println( array );
// -> [Ljava.lang.String;@6f548414
  
list.equals( Arrays.asList( "foo""bar" ) )
// -> true
array.equals( new String[] { "foo""bar" } )
// -> false

  不同于数组,集合的 API 提供了许多有用的方法来访问元素. 用户可以检查包含的元素,提取子列表或者计算交集. 集合可以向数据层添加特定的特性, 诸如线程安全,同时将实现原理保持在内部可见.

  通过使用一个数据,你定义了数据被保存在内存中的哪个地方. 通过使用一个集合,你定义了用户可以在数据上做的操作.

  数组不是类型安全的

  如果你依赖于编译器检查的类型安全,小心对象数组. 下面的代码会在运行时奔溃,但是编译器找不出问题所在:

1
2
Number[] numbers = new Integer[10];
numbers[0] = Long.valueOf( 0 ); // throws ArrayStoreException

  原因是数组是“协变式”的, 比如,如果 T 是S 的一个子类型, 那么 T[] 就会是 S[] 的一个子类型. Joshua Bloch 在其著作 Effective Java 涵盖了所有的理论, 每一个Java开发者必读.

  归因于这个行为,暴露数组类型的接口允许返回声明数组类型的一个子类型, 导致了一个怪异的运行时异常.

  Bloch 同时也解释说,数组与泛型类型不兼容. 因为数组会在运行时强制要求有类型信息,而泛型则会在编译时被检查,泛型类型不能被放到数组中.

一般而言,数组和泛型不能很好的融合。如果你发现自己在融合它们而得到了一个编译时错误或者警告,那你的第一反应应该是用list去替换数组.

  - Joshua Bloch, Effective Java (第二版), 第29条

  总结

  数组底层的语言构造、它们会被用在实现中,但是它们不应该想其它的类暴露. 在一个接口方法中使用数组违背了面向对象的原则,它会导致违和的API,并且它也可能给类型安全和性能造成短板.

  原文地址:http://eclipsesource.com/blogs/2014/04/11/3-good-reasons-to-avoid-arrays-in-java-interfaces/

Java 接口中使用数组缺点的理由相关推荐

  1. java接口如何定义常量 c_在Java接口中怎样访问定义的常量呢?

    java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能).那么我们在Java接口中怎 ...

  2. java中为按钮添加图片_我们可以在Java接口中为成员定义私有和受保护的修饰符吗?...

    java中为按钮添加图片 No, it is not possible to define private and protected modifiers for the members in int ...

  3. Java语言中的----数组

    day07  Java语言中的--数组 一.数组的概述: 什么是数组?数组是干什么用的?为啥要学数组?这些都是疑问.再你学完数组以后就知道了,数组是存储在相邻内存位置的单一数据类型的元素集合.什么是单 ...

  4. Java快速入门学习笔记8 | Java语言中的数组

    有人相爱,有人夜里开车看海,有人却连LeetCode第一题都解不出来!虽然之前系统地学习过java课程,但是到现在一年多没有碰过Java的代码,遇到LeetCode不知是喜是悲,思来想去,然后清空自己 ...

  5. java中 关于静态方法的定义_为什么我们不能在Java接口中定义静态方法?

    从Java 8开始,Java接口中允许使用静态方法. 从Java 8开始,接口也可以具有静态帮助器方法.public interface vehicle { default void print()  ...

  6. Java1.8接口方法都是抽象,判断(1分) Java接口中所有的方法都是抽象的。

    判断(1分) Java接口中所有的方法都是抽象的. 更多相关问题 [配伍题,B型题] (1).木瓜(). (2).独活().(3).防己().(4).蕲蛇(). [比较题] (1).质硬不易折断的是( ...

  7. java定义常量语法错误的是_在Java接口中定义常量,下面语法错误的是( )_学小易找答案...

    [单选题]Why did Ben's emotions change so much? [判断题]Write the title in the middle of the first line. [单 ...

  8. java接口中的抽象方法_Java中的接口与抽象方法

    Java中的接口与抽象方法 时间:2017-06-27     来源:华清远见JAVA学院 今天华清Java学院小编来和大家分享一下Java中接口和抽象方法的一些知识. Java中接口是什么? 什么是 ...

  9. java 接口中 常量_在Java接口中怎样访问定义的常量呢?

    java接口是一系列方法的声明,是一些方法特征的集合,一个接口只有方法的特征没有方法的实现,因此这些方法可以在不同的地方被不同的类实现,而这些实现可以具有不同的行为(功能).那么我们在Java接口中怎 ...

最新文章

  1. [Share]10 Free EBooks for Web Designers
  2. 0.1+0.2==0.3?
  3. createform用法_vue自定义表单生成器form-create使用详解
  4. java obervable_RxJava中Observable,Completable和Single之间有什么区别
  5. html的table属性笔记
  6. java excel导出功能_java中的Excel导出功能
  7. IntelliJ Idea学习笔记001--- IntelliJ Idea常用快捷键列表
  8. linux http用户,HTTP完整请求过程
  9. ARINC485和RS485的区别
  10. python开发:开源pytesseract文字识别
  11. PS修皮肤去痘痘毛孔,只需要掌握这个技巧就够了
  12. 知识图谱(knowledge graph)——概述
  13. 是时候要说再见了,春风十里,不如邮你!
  14. 音频处理贤内助--libsndfile
  15. 荒野猎人 但是亲眼看到还是第一次
  16. python根据词频绘制词云的函数_根据词频生成词云(Python wordcloud实现)
  17. 九宫格摆法_九宫格婚纱照摆法图片与技巧
  18. python 如何将视频文件的语音转换为文字
  19. XDUOJ题解合集(待填坑)
  20. 学完教程,不知道接下去从哪里开始做自己的第一个APP,怎么办?酷课堂iOS交流群问答(201902期)

热门文章

  1. Rocky4.2下安装金仓v7数据库(KingbaseES)
  2. jquery中的live()方法
  3. NSNotificationCenter消息通信机制介绍(KVO)
  4. 大数据分析的方法有哪些
  5. 大数据分析平台架构有哪些
  6. 数据分析前的准备工作
  7. 数据可视化如何做会更好
  8. enum ordinal java_Java中怎样由枚举常量的ordinal值获得枚举常量对象
  9. python 保存dataframe_在python2中将dataframe保存到CSV
  10. 安徽信息技术初中会考上机考试模拟_初中信息技术会考模拟试题