Recently, when I wrote some anonymous inner classes, I felt a little difficult to understand, so I reviewed this part again. I found some points that I didn’t notice before - the formal parameters of the anonymous inner class must be prefixed with final (unless the anonymous inner class does not use it)

So, how to understand the principle behind this matter?

How inner classes work

First, think about how inner classes work. We know that after the internal class is successfully compiled, it will generate a new class file.

The class file only retains references to external classes.

For example, when the parameters passed in by the outer class need to be called by the inner class, it looks like it is called directly:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class OuterClass{
public void method(final String name,final int age){
class InnerClass{
public void show(){
System.out.println("your name is " + name + " and age is " + age);

}
}
InnerClass in = new InnerClass();
in.show();
}
}

But in fact name is not directly called by the inner class, in fact it looks like this after java compilation:

1
2
3
4
5
6
7
8
9
10
public class OuterClass$InnerClass {
public InnerClass(String name,int age){
this.InnerClass$name = name;
this.InnerClass$age = age;
}

public void show(){
System.out.println("your name is " + this.InnerClass$name + " and age is " + this.InnerClass$age );
}
}

Therefore, from the above code, the internal class does not directly call the parameters passed in by the method, but the internal class backs up the passed parameters to its own interior through its own constructor, and the internal method call is actually its own properties instead of parameters of outer class methods!
With this understanding, it is easy to figure out why final is used.

Assuming that the inner class modifies the values of these parameters, the values of the original parameters do not change, which affects the consistency of the parameters.

From the programmer’s point of view, this parameter is the same, but if the value of the parameter is changed in the inner class, but the value is not changed when the external call is made, it may be very confusing, so in order to avoid this kind of embarrassing problem, the compiler designers set the parameters that can be used by inner classes to be final.

How anonymous inner classes work

OK, what’s the difference between an anonymous inner class and an inner class - it has no name.

There is no name, so it is constructed with the default no-argument constructor. If parameters are required, then give him a constructor with parameters.

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
public class Outer { 
    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        Inner inner = outer.getInner("Inner"); 
        System.out.println(inner.getName()); 
    } 
 
    public Inner getInner(final String name) { 
        return new Inner(name) { 
            private String nameStr = name; 
 
            public String getName() { 
                return nameStr; 
            } 
        }; 
    } 

 
abstract class Inner { 
    Inner(String name) { 
        System.out.println(name); 
    } 
 
    abstract String getName()


Look, here the parameter of the getInner method is final, the reason is the same as the reason for adding final to the inner class part before.

Sometimes you can also not add final

When can you not add final? If the inner class does not use it, you can not add final, which is easy to understand:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Outer { 
    public static void main(String[] args) { 
        Outer outer = new Outer(); 
        Inner inner = outer.getInner(1); 
        System.out.println(inner.f()); 
    } 
 
    public static Inner getInner(int i) { 
        return new Inner(i) { 
            public void f(){
System.out.println("f()");
}
        }; 
    } 

 
abstract class Inner { 
    Inner(int i) { 
        System.out.println(i); 
    } 
 
    abstract void f()