Java等于原始速度与对象速度 [英] Java equals primitive vs object speed

查看:64
本文介绍了Java等于原始速度与对象速度的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用Objects.equals与Primitive比较时,仅尝试测试equals的速度.如果有人需要代码:

Just tried to test speed of equals when using Objects.equals vs Primitive comparison. If somebody needs the code:

import org.junit.Test;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import org.openjdk.jmh.runner.options.TimeValue;

import java.util.Objects;
import java.util.concurrent.TimeUnit;

class BaseEquals {
    byte bytePrim;
    short shortPrim;
    int intPrim;
    long longPrim;
    float floatPrim;
    double doublePrim;
    boolean booleanPrim;
    char charPrim;

    BaseEquals() {
        bytePrim = 1;
        shortPrim = 1;
        intPrim = 1;
        longPrim = 1;
        floatPrim = 1.0f;
        doublePrim = 1.0d;
        booleanPrim = true;
        charPrim = '1';
    }
}

class EqualsObjects extends BaseEquals {

    @Override
    public int hashCode() {
        return Objects.hash(bytePrim,
                shortPrim,
                intPrim,
                longPrim,
                floatPrim,
                doublePrim,
                booleanPrim,
                charPrim);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof EqualsObjects)) {
            return false;
        }
        EqualsObjects eo = (EqualsObjects)obj;
        return Objects.equals(bytePrim, eo.bytePrim)
                && Objects.equals(shortPrim, eo.shortPrim)
                && Objects.equals(intPrim, eo.intPrim)
                && Objects.equals(longPrim, eo.longPrim)
                && Objects.equals(floatPrim, eo.floatPrim)
                && Objects.equals(doublePrim, eo.doublePrim)
                && Objects.equals(booleanPrim, eo.booleanPrim)
                && Objects.equals(charPrim, eo.charPrim);
    }
}

class EqualsPrimitives extends BaseEquals {

    @Override
    public int hashCode() {
        return Objects.hash(bytePrim,
                shortPrim,
                intPrim,
                longPrim,
                floatPrim,
                doublePrim,
                booleanPrim,
                charPrim);
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == this) {
            return true;
        }
        if (!(obj instanceof EqualsPrimitives)) {
            return false;
        }
        EqualsPrimitives eo = (EqualsPrimitives)obj;
        return bytePrim == eo.bytePrim
                && shortPrim == eo.shortPrim
                && intPrim == eo.intPrim
                && longPrim == eo.longPrim
                && Float.compare(floatPrim, eo.floatPrim) == 0
                && Double.compare(doublePrim, eo.doublePrim) == 0
                && booleanPrim == eo.booleanPrim
                && charPrim == eo.charPrim;
    }
}

public class EqualsTests {

    @State(Scope.Benchmark)
    public static class MyState {
        EqualsObjects eo1;
        EqualsObjects eo2;
        EqualsPrimitives ep1;
        EqualsPrimitives ep2;

        @Setup
        public void setup() throws Throwable {
            eo1 = new EqualsObjects();
            eo2 = new EqualsObjects();
            ep1 = new EqualsPrimitives();
            ep2 = new EqualsPrimitives();
        }
    }

    @Benchmark
    public void equalsObject(MyState state) throws Throwable {
        boolean b1 = state.eo1.equals(state.eo2);
        boolean b2 = state.eo2.equals(state.eo1);
    }

    @Benchmark
    public void equalsPrimitive(MyState state) throws Throwable {
        boolean b1 = state.ep1.equals(state.ep2);
        boolean b2 = state.ep2.equals(state.ep1);
    }

    @Test
    public void launch() throws RunnerException {
        Options options = new OptionsBuilder()
                .include(this.getClass().getName() + ".*")
                .mode(Mode.AverageTime)
                .timeUnit(TimeUnit.MICROSECONDS)
                .warmupTime(TimeValue.seconds(1))
                .warmupIterations(5)
                .measurementTime(TimeValue.seconds(5))
                .measurementIterations(10)
                .threads(2)
                .forks(1)
                .shouldFailOnError(true)
                .shouldDoGC(true)
                .build();
        new Runner(options).run();
    }
}

我最终看到的是这个结果:

What I saw in the end is this results:

Benchmark                    Mode  Cnt  Score    Error  Units
EqualsTests.equalsObject     avgt   10  0.026 ±  0.001  us/op
EqualsTests.equalsPrimitive  avgt   10  0.011 ±  0.001  us/op

您认为值得使用原始比较来具有更快的equals方法(可能在代码中的其他操作中可以忽略),还是使用Objects.equals来拥有统一的代码(不要考虑使用Double.compare和Float.compare来实现)是否在equals方法中分别使用double和float原语,对于其他原语则为==)?

Do you think it is worth using primitive comparison to have faster equals methods (probably neglectable to other operations in code), or using Objects.equals to have unified code (not to think about using Double.compare and Float.compare for double and float primitives respectively, and == for other primitives) in equals method?

推荐答案

两个代码之间的差异可以在其字节码输出中看到.

Difference between both codes can be seen within their bytecode outputs.

仅通过一条 if_icmpne 指令即可完成原始值比较,就这样.

Primitive value comparison is simply done with a single if_icmpne instruction, and thats it.

请参见 bytePrim == eo.bytePrim

20: astore_2
21: aload_0
22: getfield      #3                  // Field bytePrim:B
25: aload_2
26: getfield      #3                  // Field bytePrim:B
29: if_icmpne     246                 

另一方面,对象比较( Object.equals )要求在比较发生之前将基元装箱到其对象等效项(即,int到Integer,byte到Byte,char到Character等)..将两个原语都装箱后,将调用附加的 invokestatic 指令(Objects.equals)以完成比较(它在内部通过空检查等进行原语比较).

On the otherhand, Object comparision (Object.equals) requires primitives to be boxed to their Object equivalents (i.e. int to Integer, byte to Byte, char to Character etc.) before the comparison happens. Once both primitives are boxed, additional invokestatic instruction (Objects.equals) is invoked for completing the comparison (which internally does the primitive comparison with null checking etc.)

Objects.equals(bytePrim,eo.bytePrim)的指令

21: aload_0
22: getfield      #3                  // Field bytePrim:B
25: invokestatic  #4                  // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte;
28: aload_2
29: getfield      #3                  // Field bytePrim:B
32: invokestatic  #4                  // Method java/lang/Byte.valueOf:(B)Ljava/lang/Byte;
35: invokestatic  #30                 // Method java/util/Objects.equals:(Ljava/lang/Object;Ljava/lang/Object;)Z
38: ifeq  

这篇关于Java等于原始速度与对象速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆