Java语言支持在一个类中定义另一个类,这样被定义的类称为嵌套类。例如:
class OuterClass {
...
class NestedClass {
...
}
}
在类OuterClass中定义了一个类NestedClass,类NestedClass就被称为嵌套类。
嵌套类包括两种类型:静态和非静态。
声明了static的嵌套类,称为静态嵌套类。而没有声明static的非静态嵌套类,称为内部类。
class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
嵌套类是其外部类的成员。
非静态的内部类,可以访问外部类的静态成员和实例成员,即使成员被声明为private。
静态的嵌套类,不能直接访问外部类的实例成员。
作为外部类的一个成员,嵌套类可以被声明为private、public、protected或者包私有的。
(回想一下,外部类只能被声明为public或者包私有的)
为什么使用嵌套类?
使用嵌套类的原因包括:
逻辑分组:它是一种将只在一个地方使用的类进行逻辑分组的方法。如果一个类A只对另一个类B有用,那么将类A嵌入到类B中并将这两个类放在一起是合理的。而且嵌套之后,包会更加简单,井井有条。
提高封装性:考虑有两个顶级类A和B,其中B需要访问A的私有成员。通过将类B隐藏在类A中,可以将A的成员声明为私有,同时B可以访问它们。另外,B本身也可以隐藏起来,不被外界看到。
使代码更具可读性和可维护性:使得代码更靠近使用它的地方。
静态嵌套类
与类方法、类变量一样,静态嵌套类与其外部类相关联。
同时,和静态类方法类似,静态嵌套类不能直接引用在外部类中定义的实例变量或方法,只能通过对象引用来使用它们。
值得注意的是:静态嵌套类与它的外部类(或其他类)的实例成员进行交互,就像其他任何顶级类一样。实际上,静态嵌套类在表现行为上就是一个顶级类,只是为了包装方便,将该顶级类嵌套在另一个顶级类中。
静态嵌套类需要使用外部类的类名来进行访问:OuterClass.StaticNestedClass。
例如,为静态嵌套类创建一个对象,使用以下语法:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
(非静态)内部类
与实例方法、实例变量一样,内部类与其外部类的实例相关联,并且可以直接访问外部实例对象的方法和字段。
另外,由于内部类与实例相关联,因此内部类本身不能定义任何静态成员。
换句话说,内部类的实例对象,存在于外部类的实例中。考虑以下类:
class OuterClass {
...
class InnerClass {
...
}
}
InnerClass的实例只能存在于OuterClass的实例中,并且可以直接访问其外部实例的方法和字段。
也就是说,非静态内部类的实例,依赖于其外部类实例的存在而存在。如果没有创建外部类实例,就不可能创建非静态内部类实例。
要实例化内部类,必须先实例化外部类。使用以下语法在外部对象中创建内部对象:
OuterClass outerObject = new OuterClass();
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
另外,有两种特殊的内部类:本地类和匿名类。
隐藏
如果在特定范围(如内部类或方法定义)中的类型声明(如成员变量或者参数名),与其所在外部范围中的另一个声明具有相同的名称,则该声明将会隐藏其外部范围的声明。不能仅通过名称引用被隐藏的声明。
下面的例子,演示了这一点:
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 = 23
this.x = 1
ShadowTest.this.x = 0
这个例子定义了三个名为x的变量:类ShadowTest的成员变量、内部类FirstLevel的成员变量和方法methodInFirstLevel中的参数。
方法methodInFirstLevel中的参数x隐藏了内部类FirstLevel的变量。因此,当在方法methodInFirstLevel中使用变量x时,x指的是所在方法的参数。
如果要引用内部类FirstLevel的成员变量,可以使用关键字this来访问:
System.out.println("this.x = " + this.x);
通过外部类的类名,可以引用包含更大作用域的成员变量。
例如,下面的语句从方法methodInFirstLevel中访问类ShadowTest的成员变量:
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
参考
英文原文:https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
---转载本站文章请注明作者和出处 二进制之路(binarylife.icu),请勿用于任何商业用途---