Java内部类详解:成员/静态/局部/匿名内部类

总的来说
1.内部类通常用来解决“多重继承”的问题。
2.当你希望隐藏一个类的实现,减少工程中.java文件数量,或者这个类不想被扩展时,你可以通过匿名内部类来创建一个类的对象。
3.java虽然无法直接在语法层面上支持闭包,但是可以通过内部类来模拟一个闭包的程序结构。

1.内部类

概念:在一个类的内部再定义一个完整的类。

语法:

class Outer {
    class Inner {
    }
}

编译:Outer$Inner.class 和 Outer.class

特点:

  • 编译之后可生成独立的字节码文件

  • 内部类可直接访问外部类的私有成员,而不破坏封装

  • 可为外部类提供必要的内部功能组件

1.1 成员内部类

概念:在类的内部定义,与实例变量、实例方法同级别的类。属于外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。

语法:

// 创建内部类对象
Outer out = new Outer();
Inner in = out.new Inner(); // 特殊:不具普适性
// 成员内部类访问外部类的重名属性
Outer.this.属性名

特点:

  • 当外部类、内部类存在重名属性时,会优先访问内部类属性。

  • 成员内部类不能定义静态成员

/**

* 成员内部类

*/

public class TestMemberInnerClass {

      public static void main(String[] args) {
            Outer out = new Outer();
            //Outer.Inner in = new Outer.Inner();  //Error
            Outer.Inner in = out.new Inner(); // 特殊:不具备普适性
            out.m1();
            in.m2();
      }
}

class Outer {
      int a = 10; // 外部类:实例变量
      public Outer() {
            System.out.println("Outer()");
      }
      public void m1() {
            System.out.println("Outer class m1()");
      }
      /**
       * 成员内部类(实例层级) - 外部类被创建后,可再创建成员内部类
       */
      class Inner {
            int b = 20;
            int a = 30; // 内部类:重名实例变量
            public Inner() {
                  System.out.println("Inner()");
            }
            public void m2() {
                  System.out.println("Inner class m2()");
                  System.out.println("Outer a = " + Outer.this.a); //  10 (特殊:不具普适性)
                  System.out.println("Inner a = " + a); // 30
            }
      }
}
1.2 静态内部类

概念:不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员

特点:

  • 只能直接访问外部类的静态成员(实例成员需实例化外部类对象)
/**
* 静态内部类
*/
public class TestStaticInnerClass {
      public static void main(String[] args) {
            System.out.println(Outer.Inner.b); // 20
            // 静态内部类对象创建
            Outer.Inner in = new Outer.Inner();
            in.m2();
      }
}

class Outer {
      private static int a = 10;
      String s = "hello";
      static class Inner {
            static int b = 20;
            public void m2 () {
                  System.out.println(Outer.a); // 可访问外部类私有对象,不影响封装
                  //System.out.println(s); // 静态内部类不能访问外部类的非静态成员
                  System.out.println("Inner m2()");
            }
      }
}
1.3 局部内部类

概念:定义在外部类的成员方法中,作用范围和创建对象范围仅限于当前方法

特点:

  • 不能有静态成员(属性/方法)

  • 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final

  • 隐藏类的信息,限制类的使用范围



/**
* 局部内部类
*/
public class TestLocalInnerClass {
      public static void main(String[] args) {
            Outer out = new Outer();
            out.m1();
            System.out.println(out.p); 
            //  com.day.t2_localinnerclass2.Outer$1Inner@7852e922
            out.p.print();
      }
}

interface Printable {
      public void print();
}

class Outer {
      int a = 10;
      Printable p = null; // 接口引用 (可通过成员方法的 局部内部类 对接口引用赋值,保存对象)
      public void m1() {
            //Cannot refer to a non-final variable c inside an inner  class defined in a different in a different method
            /* final */int b = 20; // 局部内部类访问时会被自动加 final 修饰
            class Inner implements Printable {
                  int c = 30;
                  @Override
                  public void print() {
                        System.out.println(a); // 10, 访问外部类的实例成员,等价于 Outer.this.a
                        System.out.println(b); // 20, 一旦局部内部类访问外部类的局部变量,会被自动final修饰
                        System.out.println(c); // 30, 访问内部类的实例成员
                        System.out.println("local inner m2()");
                  }
            }

            // 创建对象
            Inner in = new Inner();
            System.out.println(in.c);
            // 接口引用指向实例对象
            p = new Inner();
      }
}

示例:限制类的使用范围

/**
* 局部内部类 - 限制类的使用范围
*/
public class TestLocalInnerClassForApply {
      public static void main(String[] args) {
            // 学校一年级开设新版(班主任)
            // 家长意见:我们需要经验丰富的老师
            //Teacher teacher = new AdvancedTeacher(); //new Error:类定义在成员方法内 - 局部内部类
            //teacher.teach();
            // 校方没有那么多高级老师(6个班,3位高级老师,3位初级老师)
            // 校方规则:班级奇偶编号,奇数班初级,偶数班高级
            Teacher t = School.getTeacher(1);
            t.teach();
      }
}

class School {
      public static Teacher getTeacher(int classNo) { // 封装思想:隐藏了类的信息,不能在外部new对象
            // 初级老师
            class BeginnerTeacher extends Teacher {
                  @Override
                  public void teach() {
                        System.out.println("初级老师在上课");
                  }
            }

            // 高级老师
            class AdvancedTeacher extends Teacher {
                  @Override
                  public void teach() {
                        System.out.println("高级老师在上课");
                  }
            }

            Teacher currentTeacher = null; // 返回值
            if (classNo % 2 != 0) {
                  currentTeacher = new BeginnerTeacher();
            } else {
                  currentTeacher = new AdvancedTeacher();
            }
            return currentTeacher;
      }
}

abstract class Teacher {
      public abstract void teach();
}
1.4 匿名内部类【实际编码中很常见】

概念:没有类名的局部内部类(一切特征都与局部内部类相同)

特点:

  • 必须继承一个父类或者实现一个接口

  • 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象

  • 使用场景:① 显式继承父类时 ② 实现接口时

  • 优点:可以减少代码量,书写的思路流畅

  • 缺点:可读性较差

/**
* 匿名内部类
*/
public class TestAnonymiteInnerClass {
      public static void main(String[] args) {
            Teacher t = School.getTeacher(1);
            t.teach();
      }
}

class School {
      public static Teacher getTeacher(int classNo) { // 封装思想:隐藏了类的信息,不能在外部new对象
            Teacher currentTeacher = null; // 返回值

            if (classNo % 2 != 0) {
                  // 匿名内部类
                  currentTeacher = new Teacher() {
                        @Override
                        public void teach() {
                              System.out.println("初级老师在上课");
                        }
                  };
            } else {
                  //匿名内部类 (创建了一个父类的子类对象,实现了子类中覆盖父类的方法)
                  currentTeacher = new Teacher() {
                        @Override
                        public void teach() {
                              System.out.println("高级老师在上课");
                        }                       
                  };
            }
            return currentTeacher;
      }
}

abstract class Teacher {
      public abstract void teach();
}

你可能感兴趣的:(Java内部类详解:成员/静态/局部/匿名内部类)