The Java Tutorials have been written for JDK 8.Java教程是为JDK 8编写的。Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.本页中描述的示例和实践没有利用后续版本中引入的改进,并且可能使用不再可用的技术。See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.有关Java SE 9及其后续版本中更新的语言特性的摘要,请参阅Java语言更改。
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.有关所有JDK版本的新功能、增强功能以及已删除或不推荐的选项的信息,请参阅JDK发行说明。
The Java programming language allows you to define a class within another class.Java编程语言允许您在另一个类中定义一个类。Such a class is called a nested class and is illustrated here:此类类称为嵌套类,如下所示:
class OuterClass { ... class NestedClass { ... } }
static
are called static nested classes.static
的嵌套类称为静态嵌套类。class OuterClass { ... class InnerClass { ... } static class StaticNestedClass { ... } }
A nested class is a member of its enclosing class.嵌套类是其封闭类的成员。Non-static nested classes (inner classes) have access to other members of the enclosing class, even if they are declared private.非静态嵌套类(内部类)可以访问封闭类的其他成员,即使它们被声明为私有。Static nested classes do not have access to other members of the enclosing class.静态嵌套类无权访问封闭类的其他成员。As a member of the 作为OuterClass
, a nested class can be declared private
, public
, protected
, or package private.OuterClass
的成员,嵌套类可以声明为private
、public
、protected
或package private
。(Recall that outer classes can only be declared (请记住,外部类只能声明为public
or package private.)public
或package private
。)
Compelling reasons for using nested classes include the following:使用嵌套类的令人信服的原因包括:
It is a way of logically grouping classes that are only used in one place这是一种逻辑上对只在一个地方使用的类进行分组的方法: If a class is useful to only one other class, then it is logical to embed it in that class and keep the two together.:如果一个类仅对另一个类有用,则将其嵌入该类并将两者保持在一起是合乎逻辑的。Nesting such "helper classes" makes their package more streamlined.嵌套这样的“助手类”使它们的包更加精简。
It increases encapsulation它增加了封装: Consider two top-level classes, A and B, where B needs access to members of A that would otherwise be declared 考虑两个顶级类A和B,其中B需要访问否则将被声明为private
.private
的成员。By hiding class B within class A, A's members can be declared private and B can access them.通过在类A中隐藏类B,A的成员可以声明为私有,B可以访问它们。In addition, B itself can be hidden from the outside world.此外,B本身可以对外界隐藏。
It can lead to more readable and maintainable code它可以产生更可读和可维护的代码: Nesting small classes within top-level classes places the code closer to where it is used.:在顶级类中嵌套小型类会使代码更接近使用它的位置。
As with instance methods and variables, an inner class is associated with an instance of its enclosing class and has direct access to that object's methods and fields.与实例方法和变量一样,内部类与其封闭类的实例相关联,并且可以直接访问该对象的方法和字段。Also, because an inner class is associated with an instance, it cannot define any static members itself.此外,由于内部类与实例相关联,因此它本身无法定义任何静态成员。
Objects that are instances of an inner class exist within an instance of the outer class.作为内部类实例的对象存在于外部类的实例中。Consider the following classes:考虑下面的类:
class OuterClass { ... class InnerClass { ... } }
An instance of InnerClass
can exist only within an instance of OuterClass
and has direct access to the methods and fields of its enclosing instance.InnerClass
的实例只能存在于OuterClass
的实例中,并且可以直接访问其封闭实例的方法和字段。
To instantiate an inner class, you must first instantiate the outer class.要实例化内部类,必须首先实例化外部类。Then, create the inner object within the outer object with this syntax:然后,使用以下语法在外部对象中创建内部对象:
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
There are two special kinds of inner classes:有两种特殊的内部类:
local classes and anonymous classes.
As with class methods and variables, a static nested class is associated with its outer class.与类方法和变量一样,静态嵌套类与其外部类相关联。And like static class methods, a static nested class cannot refer directly to instance variables or methods defined in its enclosing class: it can use them only through an object reference.和静态类方法一样,静态嵌套类不能直接引用其封闭类中定义的实例变量或方法:它只能通过对象引用来使用它们。Inner Class and Nested Static Class Example demonstrates this.内部类和嵌套静态类示例演示了这一点。
You instantiate a static nested class the same way as a top-level class:以与顶级类相同的方式实例化静态嵌套类:
StaticNestedClass staticNestedObject = new StaticNestedClass();
The following example, 以下示例OuterClass
, along with TopLevelClass
, demonstrates which class members of OuterClass
an inner class (InnerClass
), a nested static class (StaticNestedClass
), and a top-level class (TopLevelClass
) can access:OuterClass
与TopLevelClass
一起演示了OuterClass
的哪些类成员—内部类(InnerClass
)、嵌套静态类(StaticNestedClass
)和顶级类(TopLevelClass
)—可以访问:
public class OuterClass { String outerField = "Outer field"; static String staticOuterField = "Static outer field"; class InnerClass { void accessMembers() { System.out.println(outerField); System.out.println(staticOuterField); } } static class StaticNestedClass { void accessMembers(OuterClass outer) { // Compiler error: Cannot make a static reference to the non-static // field outerField // System.out.println(outerField); System.out.println(outer.outerField); System.out.println(staticOuterField); } } public static void main(String[] args) { System.out.println("Inner class:"); System.out.println("------------"); OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass(); innerObject.accessMembers(); System.out.println("\nStatic nested class:"); System.out.println("--------------------"); StaticNestedClass staticNestedObject = new StaticNestedClass(); staticNestedObject.accessMembers(outerObject); System.out.println("\nTop-level class:"); System.out.println("--------------------"); TopLevelClass topLevelObject = new TopLevelClass(); topLevelObject.accessMembers(outerObject); } }
public class TopLevelClass { void accessMembers(OuterClass outer) { // Compiler error: Cannot make a static reference to the non-static // field OuterClass.outerField // System.out.println(OuterClass.outerField); System.out.println(outer.outerField); System.out.println(OuterClass.staticOuterField); } }
This example prints the following output:此示例打印以下输出:
Inner class: ------------ Outer field Static outer field Static nested class: -------------------- Outer field Static outer field Top-level class: -------------------- Outer field Static outer field
Note that a static nested class interacts with the instance members of its outer class just like any other top-level class.请注意,静态嵌套类与其外部类的实例成员进行交互,就像其他顶级类一样。The static nested class 静态嵌套类StaticNestedClass
can't directly access outerField
because it's an instance variable of the enclosing class, OuterClass
.StaticNestedClass
无法直接访问outerField
,因为它是封闭类OuterClass
的实例变量。The Java compiler generates an error at the highlighted statement:Java编译器在突出显示的语句处生成错误:
static class StaticNestedClass { void accessMembers(OuterClass outer) { // Compiler error: Cannot make a static reference to the non-static // field outerField System.out.println(outerField); } }
To fix this error, access 要修复此错误,请通过对象引用访问outerField
through an object reference:outerField
:
System.out.println(outer.outerField);
Similarly, the top-level class 同样,顶级类TopLevelClass
can't directly access outerField
either.TopLevelClass
也不能直接访问outerField
。
If a declaration of a type (such as a member variable or a parameter name) in a particular scope (such as an inner class or a method definition) has the same name as another declaration in the enclosing scope, then the declaration shadows the declaration of the enclosing scope.如果特定范围(如内部类或方法定义)中的类型声明(如成员变量或参数名)与封闭范围中的另一个声明具有相同的名称,则该声明将隐藏封闭范围的声明。You cannot refer to a shadowed declaration by its name alone.不能仅通过名称引用带阴影的声明。The following example, 以下示例ShadowTest
, demonstrates this: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); } }
The following is the output of this example:以下是此示例的输出:
x = 23 this.x = 1 ShadowTest.this.x = 0
This example defines three variables named 此示例定义了三个名为x
: the member variable of the class ShadowTest
, the member variable of the inner class FirstLevel
, and the parameter in the method methodInFirstLevel
.x
的变量:类ShadowTest
的成员变量、内部类FirstLevel
的成员变量和方法methodInFirstLevel
中的参数。The variable 定义为x
defined as a parameter of the method methodInFirstLevel
shadows the variable of the inner class FirstLevel
.methodInFirstLevel
方法参数的变量x
将隐藏内部类FirstLevel
的变量。Consequently, when you use the variable 因此,在x
in the method methodInFirstLevel
, it refers to the method parameter.methodInFirstLevel
方法中使用变量x
时,它引用方法参数。To refer to the member variable of the inner class 要引用内部类FirstLevel
, use the keyword this
to represent the enclosing scope:FirstLevel
的成员变量,请使用关键字this
表示封闭范围:
System.out.println("this.x = " + this.x);
Refer to member variables that enclose larger scopes by the class name to which they belong.引用按其所属类名括起较大作用域的成员变量。For example, the following statement accesses the member variable of the class 例如,以下语句从ShadowTest
from the method methodInFirstLevel
:methodInFirstLevel
方法访问ShadowTest
类的成员变量:
System.out.println("ShadowTest.this.x = " + ShadowTest.this.x);
Serialization of inner classes, including local and anonymous classes, is strongly discouraged.强烈反对内部类(包括局部类和匿名类)的序列化。When the Java compiler compiles certain constructs, such as inner classes, it creates synthetic constructs; these are classes, methods, fields, and other constructs that do not have a corresponding construct in the source code.当Java编译器编译某些构造时,例如内部类,它会创建合成构造;这些是在源代码中没有相应构造的类、方法、字段和其他构造。Synthetic constructs enable Java compilers to implement new Java language features without changes to the JVM.合成构造使Java编译器能够实现新的Java语言特性,而无需更改JVM。However, synthetic constructs can vary among different Java compiler implementations, which means that 然而,合成结构在不同的Java编译器实现中可能有所不同,这意味着.class
files can vary among different implementations as well..class
文件在不同的实现中也可能有所不同。Consequently, you may have compatibility issues if you serialize an inner class and then deserialize it with a different JRE implementation.因此,如果序列化内部类,然后使用不同的JRE实现对其进行反序列化,则可能会出现兼容性问题。See the section Implicit and Synthetic Parameters in the section Obtaining Names of Method Parameters for more information about the synthetic constructs generated when an inner class is compiled.有关编译内部类时生成的合成构造的更多信息,请参阅获取方法参数名称一节中的隐式参数和合成参数一节。