编程技术网

关注微信公众号,定时推送前沿、专业、深度的编程技术资料。

 找回密码
 立即注册

QQ登录

只需一步,快速开始

极客时间

Java等于原始速度与对象速度:Java equals primitive vs object speed

ThomasFKJorna 面向对象 2022-5-11 10:27 5人围观

腾讯云服务器
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等于原始速度与对象速度的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程技术网(www.editcode.net)!

腾讯云服务器 阿里云服务器
关注微信
^