java内部类

本文深入探讨Java中的内部类与嵌套类的区别与联系,详细解释它们的行为表现,并提供实例说明如何正确使用这两种类。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

浅析Java内部类与嵌套类

Abstraction:
本文描述了Java语言的嵌入类、内部类的具体分类和行为表现。

1         概述
我们知道,Java是一种完全的面向对象的语言,作为对象的灵魂,类的种类是多种多样的。类大致可以分外部类和内部类两种,外部类就是我们通常使用的类,而内部类的使用要比外部类少的多,最常见的是GUI事件侦听器。内部类的应用虽然不多,但是如果能够有效的使用内部类,能达到事半功倍的效果。废话不多说,下面开始:

2         内部类和嵌套类:
要讨论内部类和嵌套类,首先要分清他们两者的区别于联系。

首先,内部类(Inner Classes)和嵌套类(Nested Classes)是指在一个类里面定义的另一个类。其次无论是内部类还是嵌套类,在编译时都被当作一个独立的整体。对于访问他们的其他对象来说(假如他们对这个类来说是可见的)他们的使用和我们通常用的类是一样的。

但是,内部类和嵌套类的区别在于:

1.         嵌套类是静态的,而内部类不是,也就是说嵌套类的实例化不需要外部类的实例。但是内部类是需要这个实例的。

2.         嵌套类可以任意声明静态成员,内部类不允许声明除了编译时常量以外的任何静态成员。这一限制也适用于静态初始化函数。

3.         嵌套类都是命名的,匿名的类声明不能声明运行时静态成员(不管声明是不是静态的)。

注意:类内部声明的接口都属于嵌入类。

下面我们来分别讨论一下他们的具体行为表现。

3         内部类
内部类是指在一个类里面以非静态形式声明的另一个类。内部类的实例化需要外部实例的存在。一个类可以拥有多个内部类,一个外部实例可以拥有多个内部类的实例。但是内部类有且只有一个外部实例,并且在实例化时就已经指定,无法更改。

3.1       内部类的分类
内部类根据访问权限不同可以分为以下一种类型:普通内部类和局部内部类。

普通内部类和局部内部类主要的区别在于作用域和访问权限的不同,普通内部类可以被所有人访问(只要访问控制符允许),而局部内部类的作用域更像一个变量,只能在定义它的函数内部被使用,其他人是无法使用这个类的。而且局部类可以访问定义它的函数中的final变量。

根据声明方式不同又可以分为:命名内部类和匿名内部类。命名内部类和匿名内部类的区别在于:

首先,命名类可以抽象的。匿名类不能为抽象,事实上,匿名内部类在编译时被隐形的声明为最终的(final)。

其次,命名类声明可以继承一个父类并实现多个接口,匿名类只能有一个父类(或者接口)。

再次,命名类可以被多次实例化,而匿名类只能在定义时被实例化一次。

最后,命名类可以声明多个构造函数并控制访问哪一个父类的构造函数,匿名类无法声明构造函数。

下面分别描述这些区别:

3.2       普通内部类
普通内部类是指在类成员定义中定义的类,这些类可以拥有访问控制符(public, private等)。如果访问控释符允许,则这些类可以被外面直接应用。普通命名内部类可以声明为一个接口,或者是抽象的。嵌入类其实是特殊的普通内部类,但由于其特殊性,故在下面独立讨论。

3.2.1       声明:
3.2.1.1       命名类:
class OuterClass{

//Outer class deflation
      class InnerNamedClass{
               //Inner class definition

}
}

3.2.1.2       匿名类:
声明匿名类时,可以使用一个类或者接口作为他的父类。

class OuterClass{
    //Outer class deflation
    Object unnamedObject = new Object(){
        //Inner class definition
    }
}

3.2.2       实例化:
3.2.2.1       命名类:
外部或静态方法:

OuterClass outerObject = new OuterClass();
OuterClass.InnerNamedClass innerObject = outerObject.new InnerNamedClass();

内部:

InnerNamedClass innerObject = new InnerNamedClass();

3.2.2.2       匿名类:
定义时即完成实例化

3.2.3       访问权限:
3.2.3.1       内部实例对外部实例的访问权限为:
外部类定义或继承的所有字段

3.2.3.2       外部实例对内部实例的访问权限为:
内部类定义或继承的所有字段

3.2.3.3       其他对象对内部实例的访问权限为:
若内部类不可见,则只能访问其超类定义的字段

若内部类可见,则可访问内部实例的非私有字段,具体情况与通常的类类似

 

3.2.4       备注:
内部类的外部实例是在构造时作为参数传给构造函数的,在SUN JDK中,保存外部实例的字段通常被声明为:

final OutterClass this$0;

3.3       局部内部类
局部内部类,是指在函数体内声明的类,这种类是局域性的,只在函数内声明后有效,他最大的特点是:可以访问定义它的函数中的final变量。

3.3.1       声明:
3.3.1.1      命名类:
class OuterClass{
    //Outer class deflation
    void aMethod(){
        class InnerNamedClass{
            //Inner class definition
        }
    }
}

3.3.1.2      匿名类:
class OuterClass{
    //Outer class deflation
    void aMethod(){
        Object unnamedObject = new Object(){
            //Inner class definition
        }
    }
}

3.3.2       实例化:
3.3.2.1      命名类:
局部类的作用域仅限定义该类的方法中,无法在外部实例化或访问,实例化方法与通常类相同

3.3.2.2      匿名类:
定义时即完成实例化

3.3.3       访问权限:
3.3.3.1      内部实例对外部实例的访问权限为:
外部类定义或继承的所有字段

定义该内部类的方法在定义类之前所定义的所有final变量

3.3.3.2      外部实例对内部实例的访问权限为:
在定义该内部类的方法中可以访问内部类定义或继承的所有字段

在外部实例的其他字段中只能访问其超类定义的字段

3.3.3.3      其他对象对内部实例的访问权限为:
只能访问其超类定义的字段

3.3.4       备注:
当试图访问一个final变量时,编译器实际上把该变量的值赋值给内部类的一个隐含字段中。编译器会自动的在构造函数中添加相应的参数。在SUN JDK中,这个隐含字段通常被命名为:val$varname

3.4       使用内部类的注意事项:
本节包括了一些使用内部类时需要注意的事项,这些事项对所有内部类都适用。

3.4.1       静态成员
首先需要注意的是,内部类不能非常量声明静态成员,任何静态成员的声明都会被当成编译错误,例如:

InnerClasses.java:12: 内部类不能有静态声明

                static String a;

                               ^

1 错误

         先要了解更加详细的信息,请参考附录A

3.4.2       访问外部实例
要在一个内部实例中访问外部实例,请使用:

OuterClass.this

3.4.3       字段覆盖
在内部类中声明的与外部类同签名的字段将覆盖外部字段,要访问外部字段请使用外部实例对象前缀。

OuterClass.this.field

OuterClass.this.Method();

4         嵌套类
嵌套类(Nested Classes)其实是普通内部类的一种特殊形式,首先它的声明是静态的,这就表示了这个类不需要外部实例。也表示了他不能访问外部类的实例字段。但是相应的,嵌套类可以拥有非常量静态成员。事实上,JDK通常把嵌套类当成一个具有特殊名字的独立类。

另外,嵌套类还拥有一种特殊形式:匿名嵌套类。前面说过,匿名类都是内部类,但是匿名嵌套类是一个特例,从理论上讲,他既不属于嵌套类,也不属于内部类。匿名嵌套类 不允许拥有非常量静态成员,但是他也没有外部实例供访问。

4.1       声明:
4.1.1       命名类:
class OuterClass{

//Outer class deflation
      static class StaticInnerNamedClass{
               //Inner class definition

}
}

4.1.2       匿名类:
class OuterClass{
    //Outer class deflation
    static Object unnamedObject = new Object(){
        //Inner class definition
    }
}

4.2       实例化
4.2.1       内部
StaticInnerNamedClass staticInnerNamedObject = new StaticInnerNamedClass();

4.2.2       外部
OuterClass.StaticInnerNamedClass staticInnerNamedObject = new OuterClass.StaticInnerNamedClass();

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值