Java最新请不要再说Java中final方法比非final性能更好了,Java面试题合集

更多:Java进阶核心知识集

包含:JVM,JAVA集合,网络,JAVA多线程并发,JAVA基础,Spring原理,微服务,Zookeeper,Kafka,RabbitMQ,Hbase,MongoDB,Cassandra,设计模式,负载均衡,数据库,一致性哈希,JAVA算法,数据结构,加密算法,分布式缓存等等

image

高效学习视频

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

  public void benchmark();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: bipush 32

2: invokestatic #2 // Method org/agoncal/sample/jmh/StringKit.getStringRandom:(I)Ljava/lang/String;

5: pop

6: return

LineNumberTable:

line 21: 0

line 22: 6

LocalVariableTable:

Start Length Slot Name Signature

0 7 0 this Lorg/agoncal/sample/jmh/Main;

RuntimeVisibleAnnotations:

0: #26()

public void benchmarkFinal();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: bipush 32

2: invokestatic #3 // Method org/agoncal/sample/jmh/StringKitFinal.getStringRandomFinal:(I)Ljava/lang/String;

5: pop

6: return

LineNumberTable:

line 26: 0

line 27: 6

LocalVariableTable:

Start Length Slot Name Signature

0 7 0 this Lorg/agoncal/sample/jmh/Main;

RuntimeVisibleAnnotations:

0: #26()

可以看到,它们在调用者上面的字节码也没有什么区别,只是方法名不一样之外。

对于 JVM 来说,它是只认字节码的,既然字节码除了方法名和修饰符一样,其他都一样,那就可以大概推测它们的性能几乎可以忽略不计了。因为调用 static final 和 static 非 final 的JVM指令是一样。

无 static 修饰


方法体是一样的,只是将它们删除了 static 的修饰。

结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

# JMH version: 1.19

VM version: JDK 1.8.0_92, VM 25.92-b14

VM invoker: /srv/jdk1.8.0_92/jre/bin/java

VM options: <none>

Warmup: 20 iterations, 1 s each

Measurement: 20 iterations, 1 s each

Timeout: 10 min per iteration

Threads: 1 thread, will synchronize iterations

Benchmark mode: Throughput, ops/time

Benchmark: org.agoncal.sample.jmh.Main.benchmark

中间忽略了预热及测试过程,这里只显示结果

Result “org.agoncal.sample.jmh.Main.benchmark”:

201306.770 ±(99.9%) 8184.423 ops/s [Average]

(min, avg, max) = (131889.934, 201306.770, 259928.172), stdev = 34653.361

CI (99.9%): [193122.347, 209491.193] (assumes normal distribution)

JMH version: 1.19

VM version: JDK 1.8.0_92, VM 25.92-b14

VM invoker: /srv/jdk1.8.0_92/jre/bin/java

VM options: <none>

Warmup: 20 iterations, 1 s each

Measurement: 20 iterations, 1 s each

Timeout: 10 min per iteration

Threads: 1 thread, will synchronize iterations

Benchmark mode: Throughput, ops/time

Benchmark: org.agoncal.sample.jmh.Main.benchmarkFinal

中间忽略了预热及测试过程,这里只显示结果

Result “org.agoncal.sample.jmh.Main.benchmarkFinal”:

196871.022 ±(99.9%) 8595.719 ops/s [Average]

(min, avg, max) = (131182.268, 196871.022, 265522.769), stdev = 36394.814

CI (99.9%): [188275.302, 205466.741] (assumes normal distribution)

Run complete. Total time: 00:13:35

Benchmark Mode Cnt Score Error Units

Main.benchmark thrpt 200 201306.770 ± 8184.423 ops/s

Main.benchmarkFinal thrpt 200 196871.022 ± 8595.719 ops/s

分析

字节码级别的差别

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

[19:20:17] emacsist:target $ diff /tmp/stringkit.log /tmp/stringkit-final.log

1,5c1,5

< Classfile /Users/emacsist/Documents/idea/logging/target/classes/org/agoncal/sample/jmh/StringKit.class

< Last modified 2017-6-15; size 1110 bytes

< MD5 checksum f61144e86f7c17dc5d5f2b2d35fac36d

< Compiled from “StringKit.java”

< public class org.agoncal.sample.jmh.StringKit


> Classfile /Users/emacsist/Documents/idea/logging/target/classes/org/agoncal/sample/jmh/StringKitFinal.class

> Last modified 2017-6-15; size 1130 bytes

> MD5 checksum 15ce17ee17fdb5f4721f0921977b1e69

> Compiled from “StringKitFinal.java”

> public class org.agoncal.sample.jmh.StringKitFinal

24c24

< #15 = Class #52 // org/agoncal/sample/jmh/StringKit


> #15 = Class #52 // org/agoncal/sample/jmh/StringKitFinal

32,33c32,33

< #23 = Utf8 Lorg/agoncal/sample/jmh/StringKit;

< #24 = Utf8 getStringRandom


> #23 = Utf8 Lorg/agoncal/sample/jmh/StringKitFinal;

> #24 = Utf8 getStringRandomFinal

47c47

< #38 = Utf8 StringKit.java


> #38 = Utf8 StringKitFinal.java

61c61

< #52 = Utf8 org/agoncal/sample/jmh/StringKit


> #52 = Utf8 org/agoncal/sample/jmh/StringKitFinal

75c75

< public org.agoncal.sample.jmh.StringKit();


> public org.agoncal.sample.jmh.StringKitFinal();

87c87

< 0 5 0 this Lorg/agoncal/sample/jmh/StringKit;


> 0 5 0 this Lorg/agoncal/sample/jmh/StringKitFinal;

89c89

< public java.lang.String getStringRandom(int);


> public final java.lang.String getStringRandomFinal(int);

91c91

< flags: ACC_PUBLIC


> flags: ACC_PUBLIC, ACC_FINAL

169c169

< 0 125 0 this Lorg/agoncal/sample/jmh/StringKit;


> 0 125 0 this Lorg/agoncal/sample/jmh/StringKitFinal;

188c188

< SourceFile: “StringKit.java”


> SourceFile: “StringKitFinal.java”

可以看到,字节码上除了名字和 final 修饰符差别外,其余的是一样的。

在调用者上面的字节码差别

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

  public void benchmark();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: new #2 // class org/agoncal/sample/jmh/StringKit

3: dup

4: invokespecial #3 // Method org/agoncal/sample/jmh/StringKit.“<init>”😦)V

7: bipush 32

9: invokevirtual #4 // Method org/agoncal/sample/jmh/StringKit.getStringRandom:(I)Ljava/lang/String;

12: pop

13: return

LineNumberTable:

line 21: 0

line 22: 13

LocalVariableTable:

Start Length Slot Name Signature

0 14 0 this Lorg/agoncal/sample/jmh/Main;

RuntimeVisibleAnnotations:

0: #30()

public void benchmarkFinal();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: new #5 // class org/agoncal/sample/jmh/StringKitFinal

3: dup

4: invokespecial #6 // Method org/agoncal/sample/jmh/StringKitFinal.“<init>”😦)V

7: bipush 32

9: invokevirtual #7 // Method org/agoncal/sample/jmh/StringKitFinal.getStringRandomFinal:(I)Ljava/lang/String;

12: pop

13: return

LineNumberTable:

line 26: 0

line 27: 13

LocalVariableTable:

Start Length Slot Name Signature

0 14 0 this Lorg/agoncal/sample/jmh/Main;

RuntimeVisibleAnnotations:

0: #30()

可以看到,它们除了名字不同之外,其他的JVM指令都是一样的。

总结

对于是否有 final 修饰的方法,对性能的影响可以忽略不计。因为它们生成的字节码除了 flags 标志位是否有 final 修饰不同之外,其他所有的JVM指令,都是一样的(对于方法本身,以及调用者本身的字节码都一样)。对于JVM来说,它执行的就是字节码,如果字节码都一样的话,那对于JVM来说,它就是同一样东西的了。

有继承

===

无 final 修饰


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

package org.agoncal.sample.jmh;

import java.util.Random;

/**

  • Created by emacsist on 2017/6/15.

*/

public abstract class StringKitAbs {

// 生成随机数字和字母,

public String getStringRandom(int length) {

String val = “”;

Random random = new Random();

// 参数length,表示生成几位随机数

for (int i = 0; i < length; i++) {

String charOrNum = random.nextInt(2) % 2 == 0 ? “char” : “num”;

// 输出字母还是数字

if (“char”.equalsIgnoreCase(charOrNum)) {

// 输出是大写字母还是小写字母

// int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;

val += (char) (random.nextInt(26) + 97);

} else if (“num”.equalsIgnoreCase(charOrNum)) {

val += String.valueOf(random.nextInt(10));

}

}

return val;

}

}

有 final 修饰


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

package org.agoncal.sample.jmh;

import java.util.Random;

/**

  • Created by emacsist on 2017/6/15.

*/

public abstract class StringKitAbsFinal {

// 生成随机数字和字母,

public final String getStringRandomFinal(int length) {

String val = “”;

Random random = new Random();

// 参数length,表示生成几位随机数

for (int i = 0; i < length; i++) {

String charOrNum = random.nextInt(2) % 2 == 0 ? “char” : “num”;

// 输出字母还是数字

if (“char”.equalsIgnoreCase(charOrNum)) {

// 输出是大写字母还是小写字母

// int temp = random.nextInt(2) % 2 == 0 ? 65 : 97;

val += (char) (random.nextInt(26) + 97);

} else if (“num”.equalsIgnoreCase(charOrNum)) {

val += String.valueOf(random.nextInt(10));

}

}

return val;

}

}

测试代码


写一个类来继承上面的抽象类,以此来测试在继承中 final 有否对多态中的影响

1

2

3

4

5

6

package org.agoncal.sample.jmh;

/**

  • Created by emacsist on 2017/6/15.

*/

public class StringKitFinal extends StringKitAbsFinal {

}

1

2

3

4

5

6

package org.agoncal.sample.jmh;

/**

  • Created by emacsist on 2017/6/15.

*/

public class StringKit extends StringKitAbs {

}

然后在基准测试中:

1

2

3

4

5

6

7

8

    @Benchmark

public void benchmark() {

new StringKit().getStringRandom(32);

}

@Benchmark

public void benchmarkFinal() {

new StringKitFinal().getStringRandomFinal(32);

}

测试结果


非 final 结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# JMH version: 1.19

VM version: JDK 1.8.0_92, VM 25.92-b14

VM invoker: /srv/jdk1.8.0_92/jre/bin/java

VM options: <none>

Warmup: 20 iterations, 1 s each

Measurement: 20 iterations, 1 s each

Timeout: 10 min per iteration

Threads: 1 thread, will synchronize iterations

Benchmark mode: Throughput, ops/time

Benchmark: org.agoncal.sample.jmh.Main.benchmark

中间忽略了预热及测试过程

Result “org.agoncal.sample.jmh.Main.benchmark”:

213462.677 ±(99.9%) 8670.164 ops/s [Average]

(min, avg, max) = (135751.428, 213462.677, 264182.887), stdev = 36710.017

CI (99.9%): [204792.513, 222132.841] (assumes normal distribution)

有 final 结果

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

# JMH version: 1.19

VM version: JDK 1.8.0_92, VM 25.92-b14

VM invoker: /srv/jdk1.8.0_92/jre/bin/java

VM options: <none>

Warmup: 20 iterations, 1 s each

Measurement: 20 iterations, 1 s each

Timeout: 10 min per iteration

Threads: 1 thread, will synchronize iterations

Benchmark mode: Throughput, ops/time

Benchmark: org.agoncal.sample.jmh.Main.benchmarkFinal

中间忽略了预热及测试过程

Result “org.agoncal.sample.jmh.Main.benchmarkFinal”:

213684.585 ±(99.9%) 8571.512 ops/s [Average]

(min, avg, max) = (133472.162, 213684.585, 267742.236), stdev = 36292.318

CI (99.9%): [205113.073, 222256.097] (assumes normal distribution)

总对比

1

2

3

4

# Run complete. Total time: 00:13:35

Benchmark Mode Cnt Score Error Units

Main.benchmark thrpt 200 213462.677 ± 8670.164 ops/s

Main.benchmarkFinal thrpt 200 213684.585 ± 8571.512 ops/s

它们字节码的区别


1

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

三面蚂蚁金服成功拿到offer后,他说他累了

三面蚂蚁金服成功拿到offer后,他说他累了

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

oughput, ops/time

Benchmark: org.agoncal.sample.jmh.Main.benchmarkFinal

中间忽略了预热及测试过程

Result “org.agoncal.sample.jmh.Main.benchmarkFinal”:

213684.585 ±(99.9%) 8571.512 ops/s [Average]

(min, avg, max) = (133472.162, 213684.585, 267742.236), stdev = 36292.318

CI (99.9%): [205113.073, 222256.097] (assumes normal distribution)

总对比

1

2

3

4

# Run complete. Total time: 00:13:35

Benchmark Mode Cnt Score Error Units

Main.benchmark thrpt 200 213462.677 ± 8670.164 ops/s

Main.benchmarkFinal thrpt 200 213684.585 ± 8571.512 ops/s

它们字节码的区别


1

总结

总的来说,面试是有套路的,一面基础,二面架构,三面个人。

最后,小编这里收集整理了一些资料,其中包括面试题(含答案)、书籍、视频等。希望也能帮助想进大厂的朋友

[外链图片转存中…(img-ILWBTiBA-1715443935611)]

[外链图片转存中…(img-PmdRwZMs-1715443935612)]

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

需要这份系统化的资料的朋友,可以点击这里获取

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值