实例内部类静态内部类局部内部类
主要特征内部类的实例引用特定的外部类的实例内部类的实例不与外部类的任何实例关联可见范围是所在的方法
可用的修饰符访问控制修饰符,abstract, final访问控制修饰符,static, abstract, finalabstract, final
可以访问外部类的哪些成员可以直接访问外部类的所有成员只能直接访问外部类的静态成员可以直接访问外部类的所有成员,并且只能访问所在方法的 final 类型的变量和参数
拥有成员类型只能拥有实例成员可以拥有静态成员和实例成员只能拥有实例成员
外部类如何访问内部类的成员必须通过内部类的实例来访问对于静态成员,可以通过内部类的完整类名来访问必须通过内部类的实例来访问
  • 内部类:定义在类结构中的另一个类,编译后,每个内部类都会生成对应的 .class 文件

  • 四种内部类:

    • 实例内部类:没有使用 static 修饰的内部类,OuterClass$InnerClass. class
    • 静态内部类:使用 static 修饰的内部类,OuterClass$InnerClass. class
    • 局部内部类:在方法中定义的内部类,OuterClass$NInnerClass. class(增加了一个数字 N,用于区分在不同方法中定义的同名的局部内部类)
    • 匿名内部类:没有名称的局部内部类,适合只需要使用一次的类,OuterClass$N
  • 特点:

    • 实例内部类不能含有 static 的变量和方法
    • 静态内部类(嵌套类)不能访问外部类的非 static 成员
    • 局部内部类及匿名内部类对象不能使用该内部类所在方法的非 final 局部变量

匿名内部类

  • 在定义匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用
  • 匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口
  • 匿名内部类不能定义构造器,不能是抽象类
  • 被匿名内部类访问的局部变量必须使用 final 修饰(从 Java 8 开始,被匿名内部类访问的局部变量自动使用了 final 修饰)

定义格式

  1. // 下面代码其实是创建了一个对象
  2. new 实现接口() 父类构造器([实参列表]) {
  3. // 匿名内部类的类体部分
  4. }
  1. // 定义匿名内部类继承 Animal,并创建这个类匿名对象
  2. new Animal() {
  3. };
  4. // 定义匿名内部类继承 Bird,并创建这个类匿名对象,之后调用 fly 方法
  5. new Bird() {
  6. public void fly() {
  7. System.out.println("飞翔");
  8. }
  9. }.fly();
  10. // 定义匿名内部类实现 IWalkable,并创建这个类匿名对象,之后调用 walk 方法
  11. new IWalkable() {
  12. @Override
  13. public void walk() {
  14. System.out.println("走路");
  15. }
  16. }.walk();
  1. // 外部类
  2. class Outer {
  3. String str1 = "Outer 实例变量";
  4. static String str2 = "Outer 类变量";
  5. // 实例内部类
  6. class Inner1 {
  7. String str1 = "Inner1 实例变量";
  8. final static String str2 = "Inner1 类变量"; // 实例内部类中不能定义类成员,除非使用 final 修饰
  9. public void doWork() {
  10. String str1 = "Inner1 局部变量";
  11. System.out.println(str1); // Inner1 局部变量
  12. System.out.println(this.str1); // Inner1 实例变量
  13. System.out.println(Outer.this.str1); // Outer 实例变量
  14. }
  15. }
  16. // 静态内部类
  17. static class Inner2 {
  18. String str1 = "Inner2 实例变量";
  19. static String str2 = "Inner2 类变量";
  20. public void doWork() {
  21. String str1 = "Inner2 局部变量";
  22. System.out.println(str1); // Inner2 局部变量
  23. System.out.println(this.str1); // Inner2 实例变量
  24. // System.out.println(Outer.this.str1); // 无法访问外部类的非静态成员
  25. System.out.println(Outer.str2); // Outer 类变量
  26. }
  27. }
  28. public void doWork() {
  29. final String STR3 = "方法中局部变量";
  30. // 局部内部类
  31. class Inner3 {
  32. String str1 = "Inner3 实例变量";
  33. // static String str2 = "Inner3 类变量"; // 局部内部类中不能定义类成员
  34. public void innerDoWork() {
  35. String str1 = "Inner3 局部变量";
  36. System.out.println(str1); // Inner3 局部变量
  37. System.out.println(this.str1); // Inner3 实例变量
  38. System.out.println(STR3); // 被局部内部类访问的局部变量必须使用final修饰
  39. // System.out.println(Outer.this.str1); // 无法访问外部类的非静态成员
  40. System.out.println(Outer.str2); // Outer 类变量
  41. }
  42. }
  43. new Inner3().innerDoWork(); // 只能在局部内部类所在的方法中创建对象
  44. }
  45. }
  46. // 测试类
  47. class InnerClassDemo {
  48. public static void main(String[] args) {
  49. // 通过外部类对象创建实例内部类对象
  50. Outer.Inner1 in1 = new Outer().new Inner1();
  51. in1.doWork();
  52. // 创建一个静态内部类对象不需要外部类对象
  53. // 直接调用静态内部类的构造器创建对象,需用完整的类名
  54. Outer.Inner2 in2 = new Outer.Inner2();
  55. in2.doWork();
  56. new Outer().doWork();
  57. }
  58. }