java 内部类(inner class)详解
优点
内部类的类别
1、成员内部类是最普通的内部类,它的定义为位于另一个类的内部,可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
注意:
当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量 外部类.this.成员方法
在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问
成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
public class OuterClass { private double radius = 0; private InnerClass getInnerClassInstance() { return new InnerClass(); } class InnerClass { //内部类 public void drawSahpe() { System.out.println(radius); //外部类的private成员 } } public static void main(String[] args) { //第一种方式: OuterClass outter = new OuterClass(); OuterClass.InnerClass inner = outter.new InnerClass(); //必须通过Outter对象来创建 inner.drawSahpe(); //第二种方式: OuterClass.InnerClass inner1 = outter.getInnerClassInstance(); inner1.drawSahpe(); } }
内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;
2、方法内部类(局部内部类)是定义在一个方法或者一个作用域里面的类,它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
非静态方法里的内部类、匿名内部类
1)、非静态方法的内部类可以访问外部类的实例变量、静态变量
2)、非静态方法的内部类可以访问方法的final变量
静态方法里的内部类、匿名内部类
1)、静态方法的内部类可以访问外部类的静态变量,但无法访问实例的外部变量
2)、静态方法的内部类可以访问方法的final变量,但无法访问方法的非final的变量
注意局部内部类就像是方法里面的一个局部变量一样,是不能有public、protected、private以及static修饰符的。
3、匿名内部类
一般使用匿名内部类的方法来编写事件监听代码。同样的,匿名内部类也是不能有访问修饰符和static修饰符的;
匿名内部类是唯一一种没有构造器的类。正因为其没有构造器,所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调。匿名内部类在编译的时候由系统自动起名为Outter$1.class。一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写。
public class Button { public void click(){ //匿名内部类,实现的是ActionListener接口 new ActionListener(){ public void onAction(){ System.out.println("click action..."); } }.onAction(); } //匿名内部类必须继承或实现一个已有的接口 public interface ActionListener{ public void onAction(); } public static void main(String[] args) { Button button=new Button(); button.click(); } }
4、静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。
静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class OuterClass { private double radius = 0; static class InnerClass { //静态内部类 public void drawSahpe() { //System.out.println(radius); //不能访问外部类的非静态成员 } } public static void main(String[] args) { OuterClass.InnerClass inner = new OuterClass.InnerClass(); } }
内部类可以直接访问外部类元素,但是外部类不可以直接访问内部类的元素
public class OuterClass { private String outerName; public class InnerClass{ private int innerName; InnerClass(){ //内部类可以访问外部类的元素 outerName="outer class"; } public void display(){ System.out.println(outerName); } } public static void main(String[] args) { OuterClass outerClass = new OuterClass(); OuterClass.InnerClass innerClass = outerClass.new InnerClass(); innerClass.display();
//outerClass.innerName; //报错,外部类不能直接访问内部类的元素 } }
内部类可以直接访问外部类属性,尽管外部类属性是用private修饰的。在创建外部类时,内部类会自动捕获一个外部类的引用,所以内部类访问外部类元素,实际上是通过他所持有外部类引用访问的。
内部类和外部类的联系
内部类是一个编译时概念,编译后外部类及其内部类会生成两个独立的class文件,内部类是一个相对独立的实体,与外部类不是is a的关系
外部类如何访问内部类元素?
public class OuterClass { public void display(){ //外部类访问内部类元素,需要通过内部类引用间接访问 InnerClass innerClass=new InnerClass(); innerClass.innerDisplay(); } public class InnerClass{ public void innerDisplay(){ System.out.println("I am inner class"); } } public static void main(String[] args) { OuterClass outerClass=new OuterClass(); outerClass.display(); } }
关于成员内部类的继承问题。一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
1)成员内部类的引用方式必须为 Outter.Inner.
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。
class WithInner { class Inner{ } } class InheritInner extends WithInner.Inner { // InheritInner() 是不能通过编译的,一定要加上形参 InheritInner(WithInner wi) { wi.super(); //必须有这句调用 } public static void main(String[] args) { WithInner wi = new WithInner(); InheritInner obj = new InheritInner(wi); } }
参考资料:
《java编程思想》
http://www.cnblogs.com/dolphin0520/