一、概述
可以将一个类的定义放在另一个类的定义内部,这就是内部类。内部类主要有如下作用:
- 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
- 内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以相互访问。但外部类不能访问内部类的实现细节,例如内部类的属性。
- 匿名内部类适合用于创建那些仅需一次使用的类。
注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。
二、成员内部类
成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量和方法,则需要通过内部类的对象来获取。
成员内部类不能含有static的变量和方法,因为成员内部类需要先创建了外部类,才能创建它自己。eg:
public class OutClass { String outName="xujian"; int outAge=25; public static void main(String[] args) { InerClass inerClass=new OutClass().new InerClass(); inerClass.inFun(); } class InerClass { int InAge=24; String InName="luyang"; private void inFun() { System.out.println("内部类方法访问外部类成员变量:"+outAge); } } }
在成员内部类要引用外部类对象时,使用OutClass.this来表示外部类对象。
在外部类创建内部类对象时,可以使用 InerClass inerClass=new OutClass().new InerClass();
在内部类的方法内能够直接访问外部类的private属性,这是因为在非静态内部类对象里,保存了一个它寄存的外部类的引用。
当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在就使用该变量,如果不存在就到该方法所在的内部类中查找,如果还不存在就到该内部类所在的外部类中查找是否存在该名字的变量,如果依然不存在,系统将出现编译错误。我们可以通过使用this、OutClass.class作为限定来区分。
综上,非静态内部类和外部类的关系为:非静态内部类对象必须存在外部类对象中,而外部类对象则不必一定有非静态内部类对象寄存其中。
三、静态内部类
如果使用static来修饰一个内部类,则这个内部类变成是外部类类相关的,属于整个外部类,而不是单独属于某个外部类的某个对象。静态内部类和普通的成员内部类的区别就是普通内部类不能有static修饰的成员,也不能包含静态类。
静态内部类的对象里只有外部类的类引用,没有外部类对象的引用。eg:
public class OutClass { static String outName="xujian"; static int outAge=25; public static void main(String[] args) { InerClass inerClass=new InerClass(); inerClass.inFun(); } static class InerClass { int InAge=24; String InName="luyang"; private void inFun() { System.out.println("内部类方法访问外部类成员变量:"+outAge); } } }
四、局部内部类
如果把一个内部类放在方法里定义,则这个内部类就是一个局部内部类,局部内部类仅在该方法里有效。因此局部内部类也无需使用访问控制符和static修饰符修饰。
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
五、匿名内部类
匿名内部类适合创建那种只需要一次使用的类。eg:
public class Test { public static void main(String[] args) { Thread thread=new Thread(new Runnable() { public void run() { System.out.println("匿名内部类..."); } }); thread.start(); } }
注意:如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译器会要求其参数引用是final的。