Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

Case Analysis of java Internal Class referencing Local variables and external Class member variables

2025-01-15 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/01 Report--

Most people do not understand the knowledge points of this article "java internal class quotes local variables and external class member variables", so the editor summarizes the following contents, detailed contents, clear steps, and has a certain reference value. I hope you can get something after reading this article. Let's take a look at this "java internal class reference local variables and external class member variables instance analysis" article.

Suppose we have the following code:

Interface Printer {public void print ();} class MyApplication {private int field = 10; public void print (final Integer param) {final long local = 100; final long local2 = param.longValue () + 100; Printer printer = new Printer () {@ Override public void print () {System.out.println ("Local value:" + local) System.out.println ("Local2 value:" + local2); System.out.println ("Parameter:" + param); System.out.println ("Field value:" + field);}; printer.print ();}}

Here, because param is used in the print () method of an anonymous inner class, it is decorated with final; local/local2 is a local variable, so it also needs final decoration; and field is a field of the external class MyApplication, so it does not need final decoration. What is the reason for this design?

I think this question should start from how Java implements anonymous inner classes. There are two points:

1. Anonymous inner classes can use variables of external classes (local or member changes to that).

2. Different methods in anonymous inner classes can share these variables.

Based on these two pieces of information, we can analyze that maybe these variables will be saved in the fields of the anonymous inner class, and their values / references will be passed into the inner class during construction. This ensures that the above two points can be achieved at the same time.

In fact, Java is designed in this way, and the so-called anonymous classes are not anonymous, but the compiler has named them for us. We can see this by the bytecode compiled by these two classes:

/ / Compiled from Printer.java (version 1.6: 50.0, super bit)

Class levin.test.anonymous.MyApplication$1 implements levin.test.anonymous.Printer {

/ / Field descriptor # 8 Llevin/test/anonymous/MyApplication

Final synthetic levin.test.anonymous.MyApplication this$0

/ / Field descriptor # 10 J

Private final synthetic long val$local2

/ / Field descriptor # 12 Ljava/lang/Integer

Private final synthetic java.lang.Integer val$param

/ / Method descriptor # 14 (Llevin/test/anonymous/MyApplication;JLjava/lang/Integer;) V

/ / Stack: 3, Locals: 5

MyApplication$1 (levin.test.anonymous.MyApplication arg0, long arg1, java.lang.Integer arg2)

0 aload_0 [this]

1 aload_1 [arg0]

2 putfield levin.test.anonymous.MyApplication$1.this$0: levin.test.anonymous.MyApplication [16]

5 aload_0 [this]

6 lload_2 [arg1]

7 putfield levin.test.anonymous.MyApplication$1.val$local2: long [18]

10 aload_0 [this]

11 aload 4 [arg2]

13 putfield levin.test.anonymous.MyApplication$1.val$param: java.lang.Integer [20]

16 aload_0 [this]

17 invokespecial java.lang.Object () [22]

20 return

Line numbers:

[pc: 0, line: 1]

[pc: 16, line: 13]

Local variable table:

[pc: 0, pc: 21] local: this index: 0 type: new levin.test.anonymous.MyApplication () {}

/ / Method descriptor # 24 () V

/ / Stack: 4, Locals: 1

Public void print ()

0 getstatic java.lang.System.out: java.io.PrintStream [30]

3 ldc [36]

5 invokevirtual java.io.PrintStream.println (java.lang.String): void [38]

8 getstatic java.lang.System.out: java.io.PrintStream [30]

11 new java.lang.StringBuilder [44]

14 dup

15 ldc [46]

17 invokespecial java.lang.StringBuilder (java.lang.String) [48]

20 aload_0 [this]

21 getfield levin.test.anonymous.MyApplication$1.val$local2: long [18]

24 invokevirtual java.lang.StringBuilder.append (long): java.lang.StringBuilder [50]

27 invokevirtual java.lang.StringBuilder.toString (): java.lang.String [54]

30 invokevirtual java.io.PrintStream.println (java.lang.String): void [38]

33 getstatic java.lang.System.out: java.io.PrintStream [30]

36 new java.lang.StringBuilder [44]

39 dup

40 ldc [58]

42 invokespecial java.lang.StringBuilder (java.lang.String) [48]

45 aload_0 [this]

46 getfield levin.test.anonymous.MyApplication$1.val$param: java.lang.Integer [20]

49 invokevirtual java.lang.StringBuilder.append (java.lang.Object): java.lang.StringBuilder [60]

52 invokevirtual java.lang.StringBuilder.toString (): java.lang.String [54]

55 invokevirtual java.io.PrintStream.println (java.lang.String): void [38]

58 getstatic java.lang.System.out: java.io.PrintStream [30]

61 new java.lang.StringBuilder [44]

64 dup

65 ldc [63]

67 invokespecial java.lang.StringBuilder (java.lang.String) [48]

70 aload_0 [this]

71 getfield levin.test.anonymous.MyApplication$1.this$0: levin.test.anonymous.MyApplication [16]

74 invokestatic levin.test.anonymous.MyApplication.access$0 (levin.test.anonymous.MyApplication): int [65]

77 invokevirtual java.lang.StringBuilder.append (int): java.lang.StringBuilder [71]

80 invokevirtual java.lang.StringBuilder.toString (): java.lang.String [54]

83 invokevirtual java.io.PrintStream.println (java.lang.String): void [38]

86 return

Line numbers:

[pc: 0, line: 16]

[pc: 8, line: 17]

[pc: 33, line: 18]

[pc: 58, line: 19]

[pc: 86, line: 20]

Local variable table:

[pc: 0, pc: 87] local: this index: 0 type: new levin.test.anonymous.MyApplication () {}

Inner classes:

[inner class info: # 1 levin/test/anonymous/MyApplication$1, outer class info: # 0

Inner name: # 0, accessflags: 0 default]

Enclosing Method: # 66 # 77 levin/test/anonymous/MyApplication.print (Ljava/lang/Integer;) V

}

/ / Compiled from Printer.java (version 1.650, super bit) class levin.test.anonymous.MyApplication {/ / Field descriptor # 6 I private int field; / / Method descriptor # 8 () V / / Stack: 2, Locals: 1 MyApplication () 0 aload_0 [this] 1 invokespecial java.lang.Object () [10] 4 aload_0 [this] 5 bipush 10 7 putfield levin.test.anonymous.MyApplication.field: int [12] 10 return Line numbers: [pc: 0, line: 7] [pc: 4, line: 8] [pc: 10, line: 7] Local variable table: [pc: 0 Pc: 11] local: this index: 0 type: levin.test.anonymous.MyApplication / / Method descriptor # 19 (Ljava/lang/Integer ) V / / Stack: 6, Locals: 7 public void print (java.lang.Integer param) 0 ldc2_w [20] 3 lstore_2 [local] 4 aload_1 [param] 5 invokevirtual java.lang.Integer.longValue (): long [22] 8 ldc2_w [20] 11 ladd 12 lstore 4 [local2] 14 new levin.test.anonymous.MyApplication$1 [28] 17 dup 18 aload_0 [this] 19 lload 4 [local2] 21 aload_1 [param] 22 invokespecial levin.test.anonymous.MyApplication$1 (levin.test.anonymous.MyApplication Long, java.lang.Integer) [30] 25 astore 6 [printer] 27 aload 6 [printer] 29 invokeinterface levin.test.anonymous.Printer.print (): void [33] [nargs: 1] 34 return Line numbers: [pc: 0, line: 11] [pc: 4, line: 12] [pc: 14, line: 13] [pc: 27 Line: 22] [pc: 34, line: 23] Local variable table: [pc: 0, pc: 35] local: this index: 0 type: levin.test.anonymous.MyApplication [pc: 0, pc: 35] local: param index: 1 type: java.lang.Integer [pc: 4, pc: 35] local: local index: 2 type: long [pc: 14 Pc: 35] local: local2 index: 4 type: long [pc: 27, pc: 35] local: printer index: 6 type: levin.test.anonymous.Printer / / Method descriptor # 45 (Llevin/test/anonymous/MyApplication ) I / / Stack: 1, Locals: 1 static synthetic int access$0 (levin.test.anonymous.MyApplication arg0); 0 aload_0 [arg0] 1 getfield levin.test.anonymous.MyApplication.field: int [12] 4 ireturn Line numbers: [pc: 0, line: 8] Inner classes: [inner class info: # 28 levin/test/anonymous/MyApplication$1, outer class info: # 0 inner name: # 0, accessflags: 0 default]}

As you can see from these two bytecodes, the compiler gave our anonymous class the name MyApplication$1, which contains three final fields (here the synthetic modifier means that these fields are generated by the compiler, they do not exist in the source code):

Application of MyApplication this$0

Long value val$local2

Integer references val$param

These fields are assigned in the constructor, which is called in the MyApplication.print () method.

From this, we can draw a conclusion: Java's implementation of the anonymous inner class is supported by the compiler, that is, the compiler helps us generate the class name of an anonymous class, and takes all the local variables and parameters used in the anonymous class as the final fields of the inner class, and the same inner class will also reference the instance of the external class. In fact, the variable local is missing here, because local is a compiler constant, and the compiler optimizes it for replacement.

In fact, a lot of syntax in Java is supported by the compiler, but there is no difference in the virtual machine / bytecode, such as the final keyword here, in fact, careful people will find that in the bytecode, the param parameter is not modified by final, and many implementations of final itself are supported by the compiler. Similarly, there are generics and inverters, covariates and so on in Java. This is beside the point.

With this foundation, we can analyze why some of them are decorated with final and some of them don't.

First of all, let's analyze the local2 variable. In the Anonymous Class, it is passed into the Anonymous Class field through the constructor, because it is the basic type, so when it reaches the assignment in the function (regardless of the different effects caused by passing different virtual machines to the function parameters), it is actually just a copy of the value. Therefore, if we add that we can assign a value to it in the print () method in the anonymous class, then the local2 variable in the external class will not be affected, and the programmer reads from top to bottom when reading the code, so it is easy to mistakenly think that this code assignment will affect the local2 variable itself in the external class, not to mention that their names are all the same in the source code. So I thought that to avoid some of the problems caused by this kind of confuse, the Java designer designed this syntax.

The same is true for reference types, because the passing of references is actually just passing the value of the reference (simply understood as an address), so for param, if you can assign a value in the "anonymous class", it will not have an impact on the print () subsequent method of the external class. Even so, we can change the value inside the reference in the inner class if the reference type is not read-only; here Integer is read-only, so we can't do that.

The above is about "java internal class reference local variables and external class member variable instance analysis" of this article, I believe we all have a certain understanding, I hope the content shared by the editor will be helpful to you, if you want to know more related knowledge, please pay attention to the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report