🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
在类内部可定义成员变量和方法,且在类内部也可以定义另一个类。如果在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)。 * 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的`.class`文件,前面冠以外部类的类名和`$`符号。 * 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。 * 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。 ## 1、成员内部类 成员内部类(实例内部类)是指没有用 static 修饰的内部类,有的地方也称为非静态内部类。示例如下: ``` public class Out { class Inner {} } ``` * 在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。 ``` public class Outer { class Inner {} Inner inner = new Inner(); // 不需要创建外部类实例 public void method1() { Inner i = new Inner(); // 不需要创建外部类实例 } public static void method2() { Inner i = new Outer().new Inner(); // 需要创建外部类实例 } } ``` * 在实例内部类中,可以访问外部类的所有成员。 ``` public class Outer { public int a = 100; static int b = 100; final int c = 100; private int d = 100; public String method3() { return "实例方法"; } public static String method4() { return "静态方法"; } class Inner { int a2 = a + 1; // 访问 public 的 a int b2 = b + 1; // 访问 static 的 b int c2 = c + 1; // 访问 final 的 c int d2 = d + 1; // 访问 private 的 d String str1 = method1(); // 访问实例方法method1 String str2 = method2(); // 访问静态方法method2 } public static void main(String[] args) { Inner in = new Outer().new Inner(); System.out.println(in.a2); // 输出 101 System.out.println(in.b2); // 输出 101 System.out.println(in.c2); // 输出 101 System.out.println(in.d2); // 输出 101 System.out.println(in.str1); // 输出实例方法 System.out.println(in.str2); // 输出静态方法 } } ``` * 在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。 * 外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。 ``` public class Outer { int a = 10; class Inner { int a = 20; int a1 = this.a; int b3 = Outer.this.a; } } ``` * 在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。 【选择】已知外部类 Out 中含有成员内部类 Inner,在主方法中怎么获取内部类 Inner 的实例化对象 inner()(选择两项) ``` A Out o = new Out(); Out.Inner inner = o.new Out(); B Out o = new Out(); Out.Inner inner = o.new Inner(); C Out.Inner inner = new Inner(); D Out.Inner inner = new Out().new Inner(); ``` ## 2、静态内部类 静态内部类是指使用 static 修饰的内部类。示例代码如下: ``` public class Outer { static class Inner {} // 静态内部类 } ``` * 在创建静态内部类的实例时,不需要创建外部类的实例。 ``` class OtherClass { Outer.Inner oi = new Outer.Inner(); } ``` * 静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例。 ``` public class Outer { static class Inner { int a = 0; static int b = 0; } } class OtherClass { Outer.Inner oi = new Outer.Inner(); int a2 = oi.a; // 访问实例成员 int b2 = Outer.Inner.b; // 访问静态成员 } ``` * 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问。 ``` public class Outer { int a = 0; static int b = 0; static class Inner { Outer o = new Outer(); int a2 = o.b; // 访问实例变量 int b2 = b; // 访问静态变量 } } ``` ## 3、方法内部类 局部内部类(方法内部类)是指在一个方法中定义的内部类。示例代码如下: ``` public class Test { public void method() { class Inner {} // 局部内部类 } } ``` * 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。 * 局部内部类只在当前方法中有效。 ``` public class Test { Inner i = new Inner(); // 编译出错 Test.Inner ti = new Test.Inner(); // 编译出错 Test.Inner ti2 = new Test().new Inner(); // 编译出错 public void method() { class Inner {} Inner i = new Inner(); } } ``` * 局部内部类中不能定义 static 成员。 * 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。 * 在局部内部类中可以访问外部类的所有成员。 * 在局部内部类中可以直接访问当前方法中的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用`外部类.this.变量`的形式访问外部类中的成员。 ``` public class Test { int a = 0; int d = 0; public void method() { int b = 0; final int c = 0; final int d = 10; class Inner { int a2 = a; // 访问外部类中的成员 int b2 = b; // 访问外部类中的成员 int c2 = c; // 访问方法中的成员 int d2 = d; // 访问方法中的成员 int d3 = Test.this.d; //访问外部类中的成员 } Inner i = new Inner(); System.out.println(i.d2); // 输出 10 System.out.println(i.d3); // 输出 0 } } ``` 【选择】关于下列代码,说法正确的是()(选择一项) ``` public class OutClass { public Object info() { // (1) public static class FunInner { // (2) public String print() { return "方法内部类"; } } return new FunInner().print(); // (3) } } ``` ``` A 代码编译成功 B 代码编译错误,错误发生在位置一 C 代码编译错误,错误发生在位置二 D 代码编译错误,错误发生在位置三 ``` ## 4、匿名内部类 匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下: ``` new <类或接口>() { // .... } ``` 这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。 匿名类有两种实现方式: * 继承一个类,重写其方法。 * 实现一个接口(可以是多个),实现其方法 ``` public class Out { void show() { System.out.println("调用 Out 类的 show() 方法"); } } public class Test { public static void main(String[] args) { Out o = new Out() { void show() { System.out.println("调用匿名类中的 show() 方法"); } } o.show(); // 调用匿名类中的 show() 方法 } } ``` * 匿名类和局部内部类一样,可以访问外部类的所有成员。 ``` public static void main(String[] args) { int a = 10; final b = 10; Out o = new Out() { void show() { System.out.println(a); // 编译通过 System.out.println(b); // 编译通过 } } o.show(); } ``` * 匿名类中允许使用非静态代码块进行成员初始化操作。 ``` Out o = new Out() { int i; { i = 10; } public void show() { System.out.println("i"); } } ``` * 匿名类的非静态代码块会在父类的构造方法之后被执行。 【选择】下面截取了一段匿名内部类的代码,关于这段代码,下面说法正确的是()(选择两项) ``` test.show(new Example() { // (1) public static int x; // (2) public abstract void show(); // (3) public void info() { // (4) System.out.println("匿名内部类"); } }); ``` ``` A 位置一错误 B 位置二错误 C 位置三错误 D 位置四错误 ``` 【编程】分别通过成员内部类、方法内部类、匿名内部类完成接口 Ball,在测试类 BallTest 的调用。程序参考运行效果图如下: ``` 成员内部类: 打篮球 ************* 方法内部类: 打乒乓球 ************* 匿名内部类: 打排球 ``` ``` public class Test { public static void main(String[] args) { // 1. 完成成员内部类内部测试 // 2. 完成方法内部类测试 // 3. 完成匿名内部类测试 } } public interface Ball { // 抽象方法 play() } public class BallTest { // 创建成员内部类 Inner_m // 创建方法内部类 // 定义一个方法 void playBall(Ball ball),调用了 play() 方法 } ```