在某些情况下,一个类会放在另一个类的内部定义,这个定义在其他类内部的类就称为内部类,包含内部类的类则被称为外部类。内部类主要有几个作用:
1.内部类提供更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问
2.内部类成员可以直接访问外部类的私有数据,因为内部类相当于外部类的成员
3.匿名内部类可用于创建那些仅需一次使用的类
内部类在定义时可以使用四种访问控制符,分别是private、省略修饰符、protected、public,依次对应仅当前类访问、同一个包中的其他类可访问、同一个包中的其他类及外部类的所有子类可访问、全部地方都可访问。
同时根据定义时的static关键字,又可细分为两种,一种用static修饰的静态内部类,另一种不用static修饰的非静态内部类,下面就详细说说它们的用法及区别:
public class outerClass{
//静态内部类
private static innerClass{
//定义静态变量
private static int staticNum;
//定义实例变量
private int num;
}
}
内部类用static修饰,代表内部类是外部类的一个静态成员,直接属于外部类。
内部可定义静态成员及实例成员
静态内部类可以直接访问外部类的静态成员,不可访问外部类的实例成员。因为静态内部类直接属于外部类,外部类实例对象不一定存在:
public class OuterClass{
private static int staticNum;
private int num;
private static InnerClass{
public void test(){
#可以访问外部类静态成员
System.out.println(staticNum);
#不可访问外部类实例成员,会报错
# System.out.println(num);
}
}
}
public class OuterClass{
#定义非静态内部类
private InnerClass{
//定义实例变量
private int num;
}
}
没有用static修饰,代表非静态内部类是外部类的一个实例成员。非静态内部类的实例必须寄存在一个外部类实例中,所以内部类实例中,会隐式保存一个外部类实例的引用。
内部只可定义实例成员,不可定义静态成员
非静态内部类可直接访问外部类的所有成员,因为非静态内部类一定有一个关联的外部类实例:
public class OuterClass{
private static int staticNum;
private int num;
private InnerClass{
public void test(){
#访问外部类静态成员
System.out.println(staticNum);
#访问外部类实例成员
System.out.println(num);
}
}
}
与使用普通类基本上没区别。外部类中不可以直接访问内部类成员,但可通过内部类名访问静态成员,或通过创建内部类对象来访问实例成员:
public class OuterClass{
#静态内部类
private static InnerClass{
private static int staticNum;
private int num;
}
#非静态内部类
private InnerClass2{
private int num;
}
public void test(){
#不可执行,会报错
# System.out.println(staticNum);
# System.out.println(num);
# 访问静态内部类静态成员
System.out.println(InnerClass.staticNum);
# 访问静态内部类实例成员
System.out.println(new InnerClass().num));
# 访问非静态内部类实例成员,同上
System.out.println(new InnerClass2().num));
}
}
有一点需要注意,外部类的静态方法及静态代码块,不可以调用非静态内部类,即静态成员不可访问非静态成员,这是Java的规则。
public class OuterClass{
#非静态内部类
private InnerClass{
private int num;
}
public static void test(){
#不可执行,会报错
# new InnerClass()
}
}
需使用外部类的类名当前缀,内部类的完整类名应为 OuterClass.InnerClass。示例如下
class OuterClass{
#静态内部类
public static InnerClass{
private static int staticNum;
private int num;
}
#非静态内部类
public InnerClass2{
private int num;
}
}
public static void main(String[] args) {
# 访问静态内部类静态成员
System.out.println(OuterClass.InnerClass.staticNum);
# 访问静态内部类实例成员
System.out.println(new OuterClass().new InnerClass().num);
# 访问非静态内部类实例成员,同上
System.out.println(new OuterClass().new InnerClass2().num);
}
当在内部类方法中访问变量时,Java会按局部变量->内部类变量->外部类变量的顺序依次查找对应名称的变量。
因此,若存在实例变量同名,可以通过this,外部类.this作为限定来区分获取:
public class OuterClass{
private int num;
private InnerClass{
private int num;
private void test(){
private int num;
#局部变量
System.out.println(num);
#内部类变量
System.out.println(this.num);
#外部类变量
System.out.println(OuterClass.this.num);
}
}
}
若存在静态变量同名,则可通过类名限定来区分获取:
public class OuterClass{
private static int num;
private static InnerClass{
private static int num;
private void test(){
private int num;
#局部变量
System.out.println(num);
#内部类变量
System.out.println(InnerClass.num);
#外部类变量
System.out.println(OuterClass.num);
}
}
}
由上可以看出,使用静态内部类比使用非静态内部类要简单得多,只要把外部类当成静态内部类的包空间,也能避免创建不必要的外部类对象造成资源浪费。因此当程序需要使用内部类时,应该优先考虑使用静态内部类。