很多学习Java的人都知道Java有内部类,但是我想大部分人在开发中都很少使用内部类编写代码。大部人也不知道内部类有什么作用。

接下来,我们就一起来聊聊内部类。

Java中有四种内部类:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

成员内部类

public class OutClass{
  private class InnerClass{
  }
}

特点:

  1. 直接在外部类中编写内部类,该内部类看起来好像是和外部类的字段方法平级的,其实并不然,因为在编译代码的时候,会将内部类单独编译成一个文件,其中文件名以$标识;

  2. 成员内部类允许使用private,protected,默认,public所有的权限修饰符修饰;

  3. 成员内部类的创建必须要依赖于外部类的实例;

  4. 成员内部类可以随意的访问成员外部类的成员变量。

静态内部类

public class OutClass{
  public static InnerClass{
  }
}

特点:

  1. 静态内部类以static关键字修饰;

  2. 静态内部类允许使用private,protected,默认,public所有的权限修饰符修饰;

  3. 静态内部类的创建不需要依赖外部类的实例,可以直接通过外部类进行创建;

  4. 静态内部类只能访问外部类的静态字段和静态方法。

局部内部类

public class OutClass{
  public void method(){
    class InnerClass{
    }
  }
}

特点:

  1. 局部内部类是在外部类方法的外部的方法内;

  2. 局部内部类不允许任何修饰符进行修饰(因为局部内部类所在的方法上已经有权限了,所有没有必要再局部内部类再设置权限);

  3. 局部内部类只能在该方法中实例化,不能通过外部实例化;

  4. 局部内部类和该方法的生命周期不一致;

  5. 局部内部类如果要访问该方法的局部变量,那么局部变量必须设置为final类型 。访问外部类的变量不必设置为final。

匿名内部类

public interface Iinner{
    void say();
}

public class OutClass{
  public void sayMethod(){
    new Iinner() {
      @Override
      public void say() {
        System.out.println("hello");
      }
    }.say();
  }
}

特点:

  1. 匿名内部类只能被调用一次;

  2. 匿名内部类可以访问外部类的成员变量,并且变量不必用final修饰;

  3. 匿名内部类可以访问方法的局部变量。

疑问点?

问题:

局部内部类访问方法局部变量,局部变量必须要加final,这是为什么呢?

回答:

首先说一下,因为局部内部类是一个类,实例化后是存放到堆中去了,而方法在它执行完毕后就销毁了,所以局部内部类一般要比方法的生命周期长。

那么问题来了,方法都销毁了,局部变量自然也没有了,如果局部内部类中还需要访问该局部变量,那不完了,找不到啊。所以局部内部类访问的局部变量并不是方法中的那个变量,编译源代码的时候,会将该局部变量拷贝一份放到局部内部类中,因为局部内部类其实也是一个单独的文件。

不过这样又有问题了,你想啊,我们在这里创建了局部内部类,并且操作了局部变量,我们是想操作方法中的局部变量啊!你给我了个副本,这怎么能行?

这样随便我们在内部类怎么折腾,方法中的局部变量都没啥影响啊,而且方法中的变量更改了,也不关局部内部类啥事啊。

为了避免出现这样的数据不统一,所有我们要禁止局部变量进行修改,要保证变量的统一。这其实也是无奈之举啊。不过对于引用型数据,我们仍然是可以修改里面的数据的,因为我们方法中的引用和局部内部类中的引用是一致的,都指向的统一地址。

使用内部类对于我们来说有什么好处呢??

  1. 我们知道Java只能单继承,使用内部类相当于变相的使我们拥有了多继承的能力;

为什么这么说呢?

因为内部类可以直接操作外部类的变量啊,既然能够操作外部类,那么我们用内部类继承某个类之后,在操作外部类变量,不就相当于外部类直接继承该类了吗?

  1. 使用内部类可以将类私有化,隐藏内部实现细节,方便以后进行修改内部实现;

  2. 使用内部类有时可以使我们的实现更加简洁,层次分明,代码优雅。(例如:如果一个类不需要外部调用,也仅仅只会被另一个类调用,那么我们完全可以将该类定义成调用类的内部类啊,这样,还隐藏了内部实现细节,还不用单独创建一个类文件。)