javaSE_8系列博客——Java语言的特性(三)--类和对象(15)--嵌套类

来源:互联网 发布:手机数据恢复哪个好 编辑:程序博客网 时间:2024/05/29 17:29

Java编程语言允许您在另一个类中定义一个类。这样的一个类叫做一个嵌套类,例如:

class OuterClass {    ...    class NestedClass {        ...    }}

嵌套类分为静态和非静态两类。声明为静态的嵌套类称为静态嵌套类。非静态嵌套类称为内部类。

class OuterClass {    ...    static class StaticNestedClass {        ...    }    class InnerClass {        ...    }}

嵌套类是其封闭类的成员。非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有的。静态嵌套类无法访问封闭类的其他成员。作为OuterClass的成员,嵌套类可以被声明为private,public,protected或private私有。 (回想一下,外部类只能被声明为public或package private。)

为什么使用嵌套类

使用嵌套类的令人信服的原因包括:

  • 这是一种仅在一个地方使用逻辑上分组的类的方法:如果类仅对另一个类有用,则将其嵌入该类并将其保持在一起是合乎逻辑的。嵌套这样的“助手类”使他们的包更加精简。
  • 它增强了封装性:考虑两个顶级类A和B,其中B需要访问A中声明为私有的的成员。通过在类A中隐藏B类,A的成员可以被声明为private,B可以访问它们。另外,B本身也可以保持对外部的不可见,隐蔽起来。
  • 它可以带来具有更好的可读性和可维护性的代码:将顶级类中的小类嵌套使得代码更接近使用的位置。

静态嵌套类

与类方法和变量一样,静态嵌套类与其外部类相关联。和静态类方法一样,静态嵌套类不能直接引用它的封闭类中定义的实例变量或方法:它只能通过对象引用来使用它们。

注意:

静态嵌套类与其外层类(和其他类)的实例成员就像任何其他顶级类一样进行交互。实际上,静态嵌套类是行为上的顶级类,已经嵌套在另一个顶级类中以便于打包。

使用封闭类名访问静态嵌套类:

OuterClass.StaticNestedClass

例如,要为静态嵌套类创建一个对象,请使用以下语法:

OuterClass.StaticNestedClass nestedObject =     new OuterClass.StaticNestedClass();

内部类

与实例方法和变量一样,内部类与其封闭类的实例相关联,并可以直接访问该对象的方法和字段。另外,因为内部类与一个实例相关联,所以它不能定义任何静态成员本身。 作为内部类的实例的对象存在于外部类的实例中。思考一下下面这种类型的代码:

class OuterClass {    ...    class InnerClass {        ...    }}

InnerClass的一个实例只能在OuterClass的一个实例中存在,并且可以直接访问其封闭实例的方法和字段。 要实例化一个内部类,必须首先实例化外部类。然后,使用以下语法在外部对象内创建内部对象:

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

内部类有两种特殊类:本地类和匿名类。

遮盖(覆盖)

如果特定作用域范围(例如内部类或方法定义)中的类型声明(例如成员变量或参数名称)与封闭范围中的另一个声明具有相同的名称,那么封闭类中的变量将被内部类或者方法定义中的变量遮盖。您不能仅仅通过其名称来引用一个被遮盖的变量声明。以下示例ShadowTest演示如下:

public class ShadowTest {    public int x = 0;    class FirstLevel {        public int x = 1;        void methodInFirstLevel(int x) {            System.out.println("x = " + x);            System.out.println("this.x = " + this.x);            System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);        }    }    public static void main(String... args) {        ShadowTest st = new ShadowTest();        ShadowTest.FirstLevel fl = st.new FirstLevel();        fl.methodInFirstLevel(23);    }}

以下是本例的输出:

x = 23this.x = 1ShadowTest.this.x = 0

此示例定义了名为x的三个变量:ShadowTest类的成员变量,内部类FirstLevel的成员变量和方法methodInFirstLevel中的参数。定义为methodInFirstLevel方法的参数的变量x遮盖了内部类FirstLevel的变量。因此,当在methodInFirstLevel方法中使用变量x时,它将引用method参数。要引用内部类FirstLevel的成员变量,请使用关键字this来表示使用封闭类:

System.out.println("this.x = " + this.x);

请参考包含较大范围的成员变量与其所属的类名称。例如,以下语句从方法methodInFirstLevel访问类ShadowTest的成员变量:

System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);

序列化

强烈反对内部类的序列化,包括本地和匿名类。当Java编译器编译某些构造(如内部类)时,会创建合成结构 ; 这些是在源代码中没有相应构造的类,方法,字段和其他结构。合成结构使Java编译器能够实现新的Java语言功能,而不会更改JVM。然而,合成结构可以在不同的Java编译器实现之间变化,这意味着.class文件也可以在不同的实现之间变化。因此,如果序列化内部类,然后使用不同的JRE实现对其进行反序列化则可能会遇到兼容性问题。有关在编译内部类时生成的合成结构的更多信息,请参阅“获取方法参数名称”部分中的“隐式和合成参数”部分。

0 0
原创粉丝点击