Java内部类

        嵌套类(nested class)和内部类(inner class)。嵌套类是一个在另一个类或者接口内部声明的类。嵌套类有两种类型:静态内部类(static inner class)和非静态嵌套类(non-static nested class)。非静态嵌套类也被称作内部类(inner class)。
        内部类有几种类型:
  • 成员内部类(member inner class)
  • 本地内部类(local inner class)
  • 匿名内部类(anonymous inner class)
        "顶层类"(top level class)一词是指没有在另一个类或者接口中进行定义的类。换句话说,顶层类的外部没有任何类把它包住。
        嵌套类的行为表现类似于一个普通的(顶层)类。嵌套类可以扩展另一个类,实现接口,变成子类的父类等。
        对于顶层类而言,嵌套类与其他的类成员(方法,字段)无异。嵌套类可以有4中访问修饰符:private、protected、default和public。这与顶层类不同,它只能有public和default两种修饰符。
        由于嵌套类是外层类的成员,静态嵌套类的行为与内部类的行为是不完全相同的。下面是是它们之间的区别:
  • 静态嵌套类可以有静态成员,内部类则不行
  • 像实例方法一样,内部类可以访问外层类的静态成员和非静态成员,包括它的private成员(因为嵌套类是外层类的成员)。静态嵌套类则只能访问外层类的静态成员(因为静态嵌套类也是外层类的静态成员)。
  • 不需要先创建其外层类的实例就可以直接创建静态嵌套类的实例。相反,在将内部类本身实例化之前,必须先创建一个包装内部类的外层类的实例。
        内部类有以下优点:
  • 内部类可以访问外层类的所有成员
  • 内部类有助于完全隐藏一个类的实现
  • 内部类提供了一种在Swing和其他基于事件的应用程序中编写监听器的快捷方法。
    静态的嵌套类
        不需要先创建外层类的实例就可以直接创建一个静态的嵌套类。
        关于静态的嵌套类,有几点需要注意:
  • 要用这种方式调用嵌套类:OuterClassName.InnerClassName
  • 实例化静态的嵌套类时,不需要创建外层类的实例
  • 必须从静态嵌套类内部访问外层类静态成员
        此外,如果一个与外层类和静态嵌套类中有同名的成员,后者会把前者遮住,但是可以利用OuterClassName.memberName的方式访问:
    成员内部类
        成员内部类是指其定义直接被另一个类或者接口的声明包装的类。只有当其引用其外层类的实例时,才会创建成员内部类的实例。为了从外层类内部创建内部类的实例,可以调用内部类的构造器,就像调用其他普通的类一样。但是如果想要从外层类的外部创建内部类的实例,则必须使用以下语法:OuterClassName.InnerClassName inner = outerClassObjectReference.new InnerClassName();
        从内部类内部,可以用this引用其实例。要引用外层类的实例,需要这个语法:OuterClassName.this
        成员内部类可以用来完全隐藏一个实现:
    局部内部类
        局部内部类(local inner class)或简称局部类(local class),从定义上将,它不属于任何其他类的成员类(因为它的声明不是直接在外层类的声明中)。局部类有名称,与没有名称的匿名类相反。
        局部类可以在任何代码块中进行声明,它的作用域是在这个块之内:
局部类可以访问外层类的成员,还可以访问局部变量。然后,你只能访问final局部变量。如果你试图访问一个非final的局部变量,编译器将会产生一个编译错误。

    匿名内部类
        匿名内部类没有名称。使用这种嵌套类是为了编写接口实现。

        此外,可以通过扩展一个抽象类或具体类来创建匿名的内部类:

深入了解嵌套类和内部类
        JVM并不了解嵌套类的概念,是编译器在努力地将内部类编译成顶层类,以外层类和内部类的名称为名,两者之间用一个美元符号分隔。也就是说,使用一个处于Outer内部名为Inner的内部类,它们会被编译成Outer.class和Outer$Inner.class。
        那么匿名内部类有如何呢?对于匿名类,编译器会尽量利用数字为它们生成一个名称。因此,你会看到像Outer$1.class、Outer$2.class等这样的名称。
        当实例化嵌套类时,该实例就是堆中的一个独立对象。它实际上并不是处在外层类对象的内部。
        然而,创建了内部类对象,它们就有了对外层类对象的一个自动引用。但是,这个引用不存在静态嵌套类的实例中,因为静态嵌套类不能访问其外层类的实例成员。
        一个内部类对象如何获得对其外层类的引用呢?这还是因为编译器在编译内部类时稍微修改了内部类的构造器,也就是说它给每个构造器都增加了一个参数。这个参数就是外层类的类型。
        例如,一个像这样的构造器:
        public Inner()
        改成:
        public Inner(Outer outer)
        这个构造器:
        public Inner(int value)
        改成:
        public Inner(Outer outer, int value)
        随着编译器将外层类对象的一个引用传递给内部类构造器,实例化内部类的代码页修改了。如果编写:
        Outer outer = new Outer();
        outer.Inner inner = outer.new Inner();
        编译器会将它改成:
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner(outer);
        当一个内部类在外层类内部实例化时,编译器当然会利用关键字this传递外层类对象的当前实例。
        现在讲解另外一个问题。嵌套类是如何访问其外层类private成员的呢?任何对象都不允许访问另一个对象的private成员。这还是因为编译器修改了代码,它创建了一个方法,用来访问外层类定义中的private成员。因此,

被编译器修改成了:

        这种添加是在编译器后台发生的,因此你在源代码是看不到。编译器添加了返回private成员值的access$0方法,因此内部类可以访问private成员。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值