内部类可以使用外部类的所有成员变量和成员方法,包括私有的。
内部类分四种
- 成员内部类(以成员的方式定义在类内部)
- 局部内部类(在方法中定义)
- 匿名内部类(没有命名)
- 静态内部类
成员内部类
定义:
public class Main {
public static void main(String[] args) {
// 方式一:通过成员方法访问内部类
Main main = new Main();
main.useInnerClass();
// 方式二:直接使用内部类
Main.InnerClass mIn = new Main().new InnerClass();
mIn.printCount();
}
private int count = 2;
protected String name = "James";
public double monney = 2.33;
/** 定义成员内部类 **/
/**
内部类使用不同的限定符,会存在差别
public 公共内部类可以在任何地方被访问,包括其它类
private 私用内部类,只能被其所定义的外部类访问,其它类均不可访问,包括子类
protected 受保护的内部类,只能被其定义的外部类及其子类访问
default 默认内部类,可以被本包内的类访问,其它类不能访问
**/
public class InnerClass{
private int innerCount;
public InnerClass(){
// 访问外部类的私有成员 count
this.innerCount = count;
}
public void printCount(){
System.out.println(innerCount);
}
}
public void useInnerClass(){
InnerClass in = new InnerClass();
in.printCount();
}
}
局部内部类
定义:
public class Main {
public static void main(String[] args) {
// 只能通过外部类的成员方法调用内部类
Main main = new Main();
main.useInnerClass();
}
private int count = 2;
protected String name = "James";
public double monney = 2.33;
public void useInnerClass(){
int methodCount = 3;
/** 定义局部内部类 **/
/**
局部内部类不能使用 public private protected 等限定符 **/
class InnerClass{
private int innerCount;
public InnerClass(){
// 访问外部类的私有成员 count
this.innerCount = count;
}
public void printCount(){
System.out.println(innerCount);
// 使用方法内局部变量
System.out.println(methodCount);
}
}
InnerClass in = new InnerClass();
in.printCount();
}
}
匿名内部类
定义:
public class Main {
public static void main(String[] args) {
new Thread(new Runnable(){
@Override
public void run(){
System.out.println("使用匿名内部类实现多线程");
}
}).start();
}
}
静态内部类
静态内部类不能访问外部类的非静态成员变量和成员方法,只能访问外部类的类成员(静态)变量和成员(静态)方法。
定义:
public class Main {
private static int a = 10;
private int c = 12;
// 静态内部类
public static class InnerClass {
private int b = 20;
public void show() {
System.out.println("外部类的a值:" + a);
// 无法访问成员变量 c :报错误 non-static variable c cannot be referenced from a static context
//System.out.println("外部类的c值:" + c);
}
}
public static void main(String[] args) {
Main.InnerClass mIn = new Main.InnerClass();
mIn.show();
}
}
静态内部类的几种用法:
- 使用静态内部类实现单例模式
public class Singleton {
private Singleton(){}
private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}
public static Singleton getInstance() {
return SingletonHolder.INSTANCE;
}
}
- 使用静态内部类实现工厂模式
public class Factory {
private Factory(){}
public static class FactoryHolder {
public static final Factory INSTANCE = new Factory();
}
public static Factory getInstance() {
return FactoryHolder.INSTANCE;
}
}
- 使用静态内部类实现多层次结构
public class OuterClass {
private OuterClass(){}
public static class InnerClass {
private InnerClass(){}
public static class InnerClass2 {
private InnerClass2(){}
}
}
}
- 使用静态内部类实现枚举类
public enum EnumClass {
A, B, C;
public static class EnumClassHolder {
public static final EnumClass[] values = EnumClass.values();
}
}
内部类初始化的时机
静态内部类
在外部类被加载的时候,静态内部类不会被加载。只有在调用静态内部类的静态方法或创建静态内部类的实例时,才会被加载,而且只会加载一次。 在以下几种情况下,内部类会被初始化
- 首次调用静态内部类的静态属性或方法时;
- 创建一个静态内部类的实例时;
- 使用反射来获取静态内部类的信息时;
- 加载外部类时,会自动加载内部类;
- 当虚拟机启动时,如果某个类是静态内部类,也会被加载。
成员内部类
在外部类被加载的时候,成员内部类不会被加载。只有在创建成员内部类的实例时,才会被加载,而且每次创建实例时,都会加载一次。
局部内部类
在外部类被加载的时候,局部内部类也不会被加载。只有进入局部内部类所在的方法体时,才会被加载,每次进入方法体时,都会被加载一次。