内部类:成员内部类,静态内部类,局部内部类,匿名内部类
定义在外部类成员区,作为外部类的一个成员。
public class Demo{ public static void main(String[] args) throws Exception { new Outer().new Inner().prints(); } } class Outer{ //外部类 private int i; class Inner{ //内部类 private int i = 1; Inner() { System.out.println("Inner"); //内部类构造函数 } void prints(){ System.out.println("Inner prints method !" + i); } } Outer() { //外部类构造方法 System.out.println("Outer"); } } /* Outer Inner Inner prints method ! 1 */
3. 当外部类和内部类成员或方法重名时默认调用内部类成员。若类的成员和内部类方法
的成员同名,则调用方法内的临时变量。
4. 例Demo编译后出现三个class文件,内部类有单独的class文件,命名方式是 外部类$内部类.class
和普通内部类一样定义在外部类成员区。只是加了static修饰词。
public class Demo{ public static void main(String[] args) throws Exception { //new Outer().new Inner().prints(); //普通内部类 new Outer.Inner().prints();//静态内部类 } } class Outer{ static class Inner{ void prints(){ int i = 2; System.out.println("Inner prints method !" + i); } } }
定义在外部类方法中的类。
public class Demo{ public static void main(String[] args) throws Exception { new Outer().inner(); } } class Outer{ private int i; public void inner(){ class Inner{ void prints(){ int i = 2; System.out.println("Inner prints method !" + i); } } new Inner().prints(); } }输出:Inner prints emthod ! 2
注意: 1.编译后仍然出现三个class文件,但命名略有不同,Outer$1Inner(). 因为临时内部类在同一个类中可能同名。所以加数字作为区分。
重复情况:
class Outer{ public void inner(){ //外部类的方法1 class Inner{ //Inner --- 1 void prints(){ //prints---1 int i = 2; System.out.println("Inner prints method !" + i); } } new Inner().prints(); }//endInner /****不会报错****/ public void inner2(){ //外部类的方法2 class Inner{ //Inner --- 2 void prints(){ // prints---2 int i = 3; System.out.println("Inner2 prints method !" + i); } } new Inner2().prints(); }//endInner2 }
2. 局部内部类等同局部变量,方法执行完毕就等待虚拟机回收,无法在方法外去引用。
3. 局部内部类在构造对象时也持有外部类的引用,所以同样不受外部类权限控制。
4. 局部内部类不能用static public private protected修饰,但可以用final。
先来看一个例子。
public class Demo{ public static void main(String[] args) throws Exception { new Outer().set(); } } abstract class Father{ abstract public void getInstance(); } class Outer{ Outer() { System.out.println("Outer"); } public void get(Father f) { f.getInstance(); } public void set() { get(new Father(){ @Override public void getInstance(){ System.out.println("I am a Father !"); } //end getInstance } //end 匿名内部类,整个匿名内部类只有这一个方法,整个类体到此结束 );//end get()方法刚刚结束! }//end set()方法结束! }输出:
Outer
I am a Father !
例子中Father类作为abstract是不能实例化的,但在Outer类的set()中
public void set() { get(new Father(){ @Override public void getInstance(){ System.out.println("I am a Father !"); } } );//endget,注意形式是get( new Father() { 方法 } ); }却可以看到有一个new Father() !是错了吗?再来看一下生成的文件:
有四个?! Outer$1.class是什么?!
我们来看一下:
很明显有一个Outer$1类继承了Father.被实例化的不是Father而是它的子类!
但我们知道JAVA类名字不能以数字开头,所以很明显这就是get方法中被传入的匿名类,命名规则就是 Outer$数字 作为名字。默认是继承Father. 也就是说在new的时候用的哪个类的名字,这个匿名内部类就是继承哪个类,并且持有父类的指针。但并不能访问父类的私有成员,因为只是继承关系。
类有继承关系,接口有实现关系,所以接口也是可以有匿名内部类。写图形界面的时候的事件监听器的注册就是匿名内部类的形式,只不过不是类而是接口而已。匿名内部类大多作为实参传给函数。一个常见的例子:
firstButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { getTxtValue().setText("事件触发!"); } });其中ActionListener是一个接口,匿名内部类被回调成为接口类型对象注册监听器,是多态的一种体现。