7.1概念

定义:

在类 Outer 的内部再定义一个类 Inner,此时类 Inner 就称为内部类(或称为嵌套类),而类 Outer 则称为外部类(或称为宿主类)

分类:

  • 实例内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

7、内部类 - 图1

特点

  1. 内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
  2. 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否为 private 的。
  3. 内部类声明成静态的,就不能随便访问外部类的成员变量,仍然是只能访问外部类的静态成员变量。

注意事项

  • 外部类只有两种访问级别:public 和默认;内部类则有 4 种访问级别:public、protected、 private 和默认。
  • 在外部类中可以直接通过内部类的类名访问内部类。
  1. InnerClass ic = new InnerClass(); // InnerClass为内部类的类名
  • 在外部类以外的其他类中则需要通过内部类的完整类名访问内部类。
  1. Test.InnerClass ti = newTest().new InnerClass(); // Test.innerClass是内部类的完整类名
  • 内部类与外部类不能重名。

7.2实例内部类

概念

实例内部类是指没有用 static 修饰的内部类,有的地方也称为非静态内部类

  1. public class Outer {
  2. class Inner {
  3. // 实例内部类
  4. }
  5. }

特点

  • 在外部类的静态方法和外部类以外的其他类中,必须通过外部类的实例创建内部类的实例。
  1. public class Outer {
  2. class Inner1 {
  3. }
  4. Inner1 i = new Inner1(); // 不需要创建外部类实例
  5. public void method1() {
  6. Inner1 i = new Inner1(); // 不需要创建外部类实例
  7. }
  8. public static void method2() {
  9. Inner1 i = new Outer().new inner1(); // 需要创建外部类实例
  10. }
  11. class Inner2 {
  12. Inner1 i = new Inner1(); // 不需要创建外部类实例
  13. }
  14. }
  15. class OtherClass {
  16. Outer.Inner i = new Outer().new Inner(); // 需要创建外部类实例
  17. }
  • 在实例内部类中,可以访问外部类的所有成员。
  • 在外部类中不能直接访问内部类的成员,而必须通过内部类的实例去访问。如果类 A 包含内部类 B,类 B 中包含内部类 C,则在类 A 中不能直接访问类 C,而应该通过类 B 的实例去访问类 C。
  • 外部类实例与内部类实例是一对多的关系,也就是说一个内部类实例只对应一个外部类实例,而一个外部类实例则可以对应多个内部类实例。
  • 如果实例内部类 B 与外部类 A 包含有同名的成员 t,则在类 B 中 t 和 this.t 都表示 B 中的成员 t,而 A.this.t 表示 A 中的成员 t
  • 在实例内部类中不能定义 static 成员,除非同时使用 final 和 static 修饰。

7.3静态内部类

概念

静态内部类是指使用 static 修饰的内部类。

  1. 纯文本复制
  2. public class Outer {
  3. static class Inner {
  4. // 静态内部类
  5. }
  6. }

特点

  • 在创建静态内部类的实例时,不需要创建外部类的实例
  1. public class Outer {
  2. static class Inner {
  3. }
  4. }
  5. class OtherClass {
  6. Outer.Inner oi = new Outer.Inner();
  7. }
  • 静态内部类中可以定义静态成员和实例成员。外部类以外的其他类需要通过完整的类名访问静态内部类中的静态成员,如果要访问静态内部类中的实例成员,则需要通过静态内部类的实例
  1. public class Outer {
  2. static class Inner {
  3. int a = 0; // 实例变量a
  4. static int b = 0; // 静态变量 b
  5. }
  6. }
  7. class OtherClass {
  8. Outer.Inner oi = new Outer.Inner();
  9. int a2 = oi.a; // 访问实例成员
  10. int b2 = Outer.Inner.b; // 访问静态成员
  11. }
  • 静态内部类可以直接访问外部类的静态成员,如果要访问外部类的实例成员,则需要通过外部类的实例去访问
    1. public class Outer {
    2. int a = 0; // 实例变量
    3. static int b = 0; // 静态变量
    4. static class Inner {
    5. Outer o = new Outer;
    6. int a2 = o.a; // 访问实例变量
    7. int b2 = b; // 访问静态变量
    8. }
    9. }

7.4局部内部类

概念

局部内部类是指在一个方法中定义的内部类。

  1. public class Test {
  2. public void method() {
  3. class Inner {
  4. // 局部内部类
  5. }
  6. }
  7. }

特点

  • 局部内部类与局部变量一样,不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰
  • 局部内部类只在当前方法中有效

    1. public class Test {
    2. Inner i = new Inner(); // 编译出错
    3. Test.Inner ti = new Test.Inner(); // 编译出错
    4. Test.Inner ti2 = new Test().new Inner(); // 编译出错
    5. public void method() {
    6. class Inner{
    7. }
    8. Inner i = new Inner();
    9. }
    10. }
  • 局部内部类中不能定义 static 成员

  • 局部内部类中还可以包含内部类,但是这些内部类也不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰。
  • 在局部内部类中可以访问外部类的所有成员
  • 在局部内部类中只可以访问当前方法中 final 类型的参数与变量。如果方法中的成员与外部类中的成员同名,则可以使用 .this. 的形式访问外部类中的成员

7.5匿名内部类重要

概念

匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:

  1. new <类或接口>() {
  2. // 类的主体
  3. };

这种形式的 new 语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口。使用匿名类可使代码更加简洁、紧凑,模块化程度更高。

格式

  1. new 父类名或接口名(){
  2. //方法重写
  3. @override
  4. public void method(){
  5. //执行语句
  6. }
  7. }

实现方式

  • 继承一个类,重写其方法。
  • 实现一个接口(可以是多个),实现其方法
  1. public class Out {
  2. void show() {
  3. System.out.println("调用 Out 类的 show() 方法");
  4. }
  5. }
  6. public class TestAnonymousInterClass {
  7. // 在这个方法中构造一个匿名内部类
  8. private void show() {
  9. Out anonyInter = new Out() {
  10. // 获取匿名内部类的实例
  11. void show() {
  12. System.out.println("调用匿名类中的 show() 方法");
  13. }
  14. };
  15. anonyInter.show();
  16. }
  17. public static void main(String[] args) {
  18. TestAnonymousInterClass test = new TestAnonymousInterClass();
  19. test.show();
  20. }
  21. }

特点

  • 匿名类和局部内部类一样,可以访问外部类的所有成员。如果匿名类位于一个方法中,则匿名类只能访问方法中 final 类型的局部变量和参数
  1. public static void main(String[] args) {
  2. int a = 10;
  3. final int b = 10;
  4. Out anonyInter = new Out() {
  5. void show() {
  6. // System.out.println("调用了匿名类的 show() 方法"+a); // 编译出错
  7. System.out.println("调用了匿名类的 show() 方法"+b); // 编译通过
  8. }
  9. };
  10. anonyInter.show();
  11. }
  • 匿名类中允许使用非静态代码块进行成员初始化操作

    1. Out anonyInter = new Out() {
    2. int i; { // 非静态代码块
    3. i = 10; //成员初始化
    4. }
    5. public void show() {
    6. System.out.println("调用了匿名类的 show() 方法"+i);
    7. }
    8. };
  • 匿名类的非静态代码块会在父类的构造方法之后被执行