In the Java Improvement Chapter - Detailed Explanation of Internal Classes, anonymous internal classes are briefly introduced. However, there are many other detailed problems with internal classes, so this blog was derived. In this blog, you can learn about the use of anonymous inner classes, things to pay attention to in anonymous inner classes, how to initialize anonymous inner classes, and why the formal parameters used by anonymous inner classes must be final.
1. Use anonymous inner classes Internal classes
Since anonymous inner classes have no names, the way they are created is a bit strange. The creation format is as follows:
new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 }
Here we see that to use anonymous inner classes we must inherit a parent class or implement an interface. Of course, we can only inherit one parent class or implement an interface. At the same time, it does not have the class keyword, because anonymous inner classes directly use new to generate a reference to an object. Of course this reference is implicit.
public abstract class Bird { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract int fly(); } public class Test { public void test(Bird bird){ System.out.println(bird.getName() + "能够飞 " + bird.fly() + "米"); } public static void main(String[] args) { Test test = new Test(); test.test(new Bird() { public int fly() { return 10000; } public String getName() { return "大雁"; } }); } } ------------------ Output: 大雁能够飞 10000米
In the Test class, the test() method accepts a Bird type parameter. At the same time, we know that there is no way to directly new an abstract class. We must first have an implementation class before we can new its implementation class instance. So use the anonymous inner class directly in the main method to create a Bird instance.
Since an anonymous inner class cannot be an abstract class, it must implement all abstract methods in its abstract parent class or interface.名 For this anonymous internal code, it can actually be split into the following form:
public class WildGoose extends Bird{ public int fly() { return 10000; } public String getName() { return "大雁"; } } WildGoose wildGoose = new WildGoose(); test.test(wildGoose);
Here the system will create an object that inherits anonymous class from the Bird class, which is transformed into a reference to Bird type.
There is a flaw in the use of anonymous inner classes, that is, they can only be used once. When creating an anonymous inner class, it will immediately create an instance of the class, and the definition of the class will disappear immediately, so the anonymous inner class It cannot be reused. For the above example, if we need to use the inner class in the test() method multiple times, it is recommended to redefine the class instead of using an anonymous inner class.
2. Precautions
In the process of using anonymous inner classes, we need to pay attention to the following points:
1. When using anonymous inner classes, we must inherit a class or implement an interface, but both You can't have both, and you can only inherit one class or implement one interface.
2. Constructors cannot be defined in anonymous inner classes.
3. There cannot be any static member variables and static methods in anonymous inner classes.
4. Anonymous inner classes are local inner classes, so all restrictions on local inner classes also apply to anonymous inner classes.
5. An anonymous inner class cannot be abstract. It must implement all abstract methods of the inherited class or implemented interface.
3. Why should the formal parameters used be final
When we pass parameters to anonymous inner classes, if the formal parameter needs to be used in the inner class, then the formal parameter must be final. That is to say: when the formal parameter of the method needs to be used in the inner class, the formal parameter must be final.
Why does it have to be final?
First of all, we know that after the internal class is compiled successfully, it will generate a class file. This class file is not the same class file as the external class, but only retains a reference to the external class. When the parameters passed in by the external class need to be called by the internal class, from the perspective of the Java program, they are called directly:
public class OuterClass { public void display(final String name,String age){ class InnerClass{ void display(){ System.out.println(name); } } } }
From the above code, it seems that the name parameter should be called directly by the internal class? In fact, it is not the case. The actual operation after java compilation is as follows:
public class OuterClass$InnerClass { public InnerClass(String name,String age){ this.InnerClass$name = name; this.InnerClass$age = age; } public void display(){ System.out.println(this.InnerClass$name + "----" + this.InnerClass$age ); } }
So judging from the above code, the internal class does not directly call the parameters passed by the method, but uses its own constructor to back up the parameters passed in. What the method calls is actually its own properties rather than the parameters passed in by the external method.
直到这里还没有解释为什么是final?在内部类中的属性和外部方法的参数两者从外表上看是同一个东西,但实际上却不是,所以他们两者是可以任意变化的,也就是说在内部类中我对属性的改变并不会影响到外部的形参,而然这从程序员的角度来看这是不可行的,毕竟站在程序的角度来看这两个根本就是同一个,如果内部类该变了,而外部方法的形参却没有改变这是难以理解和不可接受的,所以为了保持参数的一致性,就规定使用final来避免形参的不改变。
简单理解就是,拷贝引用,为了避免引用值发生改变,例如被外部类的方法修改等,而导致内部类得到的值不一致,于是用final来让该引用不可改变。
故如果定义了一个匿名内部类,并且希望它使用一个其外部定义的参数,那么编译器会要求该参数引用是final的。
四、匿名内部类初始化
我们一般都是利用构造器来完成某个实例的初始化工作的,但是匿名内部类是没有构造器的!那怎么来初始化匿名内部类呢?使用构造代码块!利用构造代码块能够达到为匿名内部类创建一个构造器的效果。
public class OutClass { public InnerClass getInnerClass(final int age,final String name){ return new InnerClass() { int age_ ; String name_; //构造代码块完成初始化工作 { if(0 < age && age < 200){ age_ = age; name_ = name; } } public String getName() { return name_; } public int getAge() { return age_; } }; } public static void main(String[] args) { OutClass out = new OutClass(); InnerClass inner_1 = out.getInnerClass(201, "chenssy"); System.out.println(inner_1.getName()); InnerClass inner_2 = out.getInnerClass(23, "chenssy"); System.out.println(inner_2.getName()); } }
更多详解匿名内部类相关文章请关注PHP中文网!