Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么不再在HashMap.clear()中使用Arrays.fill()?_Java_Arrays_Hashmap_Java 8 - Fatal编程技术网

Java 为什么不再在HashMap.clear()中使用Arrays.fill()?

Java 为什么不再在HashMap.clear()中使用Arrays.fill()?,java,arrays,hashmap,java-8,Java,Arrays,Hashmap,Java 8,我注意到HashMap.clear()的实现有些奇怪。这是它的外观: 这就是它的外观: public void clear(){ 节点[]选项卡; modCount++; 如果((制表符=表格)!=null&&size>0){ 尺寸=0; 对于(int i=0;i潜在的绩效收益并不是那么微不足道的,如果你考虑所有涉及的事情: JVM不需要解析数组类,也不需要在需要时加载和初始化它。这是一个非常重要的过程,JVM执行几个步骤。首先,它检查类加载器以查看类是否已经加载,并且每次调用方法时都会发生这种

我注意到
HashMap.clear()
的实现有些奇怪。这是它的外观:

这就是它的外观:

public void clear(){
节点[]选项卡;
modCount++;
如果((制表符=表格)!=null&&size>0){
尺寸=0;
对于(int i=0;i
我知道现在对于空映射,
可以为null,因此需要在局部变量中进行额外的检查和缓存。但是为什么用for循环替换了
Arrays.fill()


这一变化似乎是在年引入的。不幸的是,我没有找到解释为什么普通for循环可能比
Arrays.fill()
更好。速度快吗?还是更安全?

两个版本的循环在功能上没有实际差异<代码>数组。填充
执行完全相同的操作

因此,使用与否的选择不一定被认为是错误的。当涉及到这种微观管理时,由开发人员决定

每种方法都有两个单独的关注点:

  • 使用
    Arrays.fill
    可以减少代码的冗长程度,提高代码的可读性
  • 直接在
    HashMap
    代码(如版本8)中循环性能方面实际上是一个更好的选择。虽然插入
    数组
    类的开销可以忽略不计,但当涉及到像
    HashMap
    这样的广泛应用时,它的开销可能会更小,在这种应用中,每一点性能增强都会产生巨大的影响(想象一下,在成熟的webapp中,HashMap的最小占用空间减少)。考虑到Arrays类仅用于这一个循环这一事实。更改足够小,不会降低clear方法的可读性
如果不询问开发人员这是谁做的,就无法找到确切的原因,但是我怀疑这不是一个错误,就是一个小小的改进。 更好的选择


我的意见是,这可以被认为是一种改进,即使只是偶然的

对我来说,原因可能是性能的提高,而代码清晰度方面的成本可以忽略不计

请注意,
fill
方法的实现非常简单,它是一个将每个数组元素设置为null的简单for循环。因此,用实际实现替换对它的调用不会导致调用方方法的清晰性/简洁性的任何显著降低

P>潜在的绩效收益并不是那么微不足道的,如果你考虑所有涉及的事情:

  • JVM不需要解析
    数组
    类,也不需要在需要时加载和初始化它。这是一个非常重要的过程,JVM执行几个步骤。首先,它检查类加载器以查看类是否已经加载,并且每次调用方法时都会发生这种情况;当然,这里涉及到一些优化,但仍然需要一些努力。如果未加载该类,JVM将需要经历昂贵的加载过程,验证字节码,解决其他必要的依赖关系,最后执行该类的静态初始化(这可能是任意昂贵的)。鉴于
    HashMap
    是一个如此核心的类,而
    Arrays
    是一个如此庞大的类(3600多行),避免这些成本可能会带来显著的节约

  • 由于没有
    Arrays.fill(…)
    方法调用,JVM不必决定是否/何时将方法内联到调用方的主体中。由于
    HashMap#clear()
    经常被调用,JVM最终将执行内联,这需要JIT重新编译
    clear
    方法。在没有方法调用的情况下,
    clear
    将始终以最高速度运行(一旦初始JIT)


  • 不再在
    数组中调用方法的另一个好处是,它简化了
    java.util
    包中的依赖关系图,因为删除了一个依赖关系。

    我将在这里暗中拍摄

    我的猜测是,它可能已被更改,以便为(即泛型而非基本类型)奠定基础。也许(我坚持也许),这一改变是为了在专业化成为JDK的一部分的情况下更容易过渡到Java10

    如果您查看,语言限制部分,它会显示以下内容:

    由于任何类型变量都可以采用值和引用类型,因此涉及此类类型变量的类型检查规则(此后称为“avars”)。例如,对于avar T:

    • 无法将null转换为类型为T的变量
    • 无法将T与null进行比较
    • 无法将T转换为对象
    • 无法将T[]转换为对象[]
    (重点是我的)

    在前面的专门化转换部分中,它说:

    当专门化任何泛型类时,专门化器将执行许多转换,大多数是本地化的,但有些转换需要类或方法的全局视图,包括:

    • 对所有方法的签名执行类型变量替换和名称篡改
    随后,在文件末尾的进一步调查部分,它说:

    虽然我们的实验已经证明,以这种方式进行专门化是可行的,但还需要进行更多的研究。具体来说,我们需要针对任何核心JDK库,特别是集合和流,执行一些有针对性的实验


    现在,关于变化

    如果将专门化
    Arrays.fill(Object[]array,Object value)
    方法,则其签名应更改为
    Arrays.fill(
    
    public void clear() {
        modCount++;
        Arrays.fill(table, null);
        size = 0;
    }
    
    public void clear() {
        Node<K,V>[] tab;
        modCount++;
        if ((tab = table) != null && size > 0) {
            size = 0;
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }
    
    public class HashMapTest {
        public static void main(String[] args) {
            new java.util.HashMap();
        }
    }
    
    ... 155 lines skipped ...
    [Loaded java.util.Set from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.AbstractSet from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$EmptySet from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$EmptyList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$EmptyMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$UnmodifiableCollection from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$UnmodifiableList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.Collections$UnmodifiableRandomAccessList from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.Reflection from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    **[Loaded java.util.HashMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.HashMap$Node from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.Class$3 from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.Class$ReflectionData from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.Class$Atomic from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.generics.repository.AbstractRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.generics.repository.GenericDeclRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.generics.repository.ClassRepository from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.Class$AnnotationData from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.annotation.AnnotationType from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.util.WeakHashMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.ClassValue$ClassValueMap from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.reflect.Modifier from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded sun.reflect.LangReflectAccess from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    [Loaded java.lang.reflect.ReflectAccess from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    **[Loaded java.util.Arrays from C:\Program Files\Java\jre1.8.0_60\lib\rt.jar]
    ...
    
    36       3  java.util.WeakHashMap::clear (50 bytes)
         !m        @ 4   java.lang.ref.ReferenceQueue::poll (28 bytes)
                     @ 17   java.lang.ref.ReferenceQueue::reallyPoll (66 bytes)   callee is too large
                   @ 28   java.util.Arrays::fill (21 bytes)
         !m        @ 40   java.lang.ref.ReferenceQueue::poll (28 bytes)
                     @ 17   java.lang.ref.ReferenceQueue::reallyPoll (66 bytes)   callee is too large
                   @ 1   java.util.AbstractMap::<init> (5 bytes)   inline (hot)
                     @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
                   @ 9   java.lang.ref.ReferenceQueue::<init> (27 bytes)   inline (hot)
                     @ 1   java.lang.Object::<init> (1 bytes)   inline (hot)
                     @ 10   java.lang.ref.ReferenceQueue$Lock::<init> (5 bytes)   unloaded signature classes
                   @ 62   java.lang.Float::isNaN (12 bytes)   inline (hot)
                   @ 112   java.util.WeakHashMap::newTable (8 bytes)   inline (hot)
    
    void jdk7clear() {
        Arrays.fill(table, null);
    }
    
    void jdk8clear() {
        Object[] tab;
        if ((tab = table) != null) {
            for (int i = 0; i < tab.length; ++i)
                tab[i] = null;
        }
    }
    
    Map size |  JDK 7 (sd)|  JDK 8 (sd)| JDK 8 vs 7
           16|   2267 (36)|   1521 (22)| 67%
           64|   3781 (63)|   1434 ( 8)| 38%
          256|   3092 (72)|   1620 (24)| 52%
         1024|   4009 (38)|   2182 (19)| 54%
         4096|   8622 (11)|   4732 (26)| 55%
        16384|  27478 ( 7)|  12186 ( 8)| 44%
        65536| 104587 ( 9)|  46158 ( 6)| 44%
       262144| 445302 ( 7)| 183970 ( 8)| 41%
    
    Map size |  JDK 7 (sd)|  JDK 8 (sd)| JDK 8 vs 7
           16|     75 (15)|     65 (10)|  87%
           64|    116 (34)|     90 (15)|  78%
          256|    246 (36)|    191 (20)|  78%
         1024|    751 (40)|    562 (20)|  75%
         4096|   2857 (44)|   2105 (21)|  74%
        16384|  13086 (51)|   8837 (19)|  68%
        65536|  52940 (53)|  36080 (16)|  68%
       262144| 225727 (48)| 155981 (12)|  69%