很多学习Java的人都知道Java有内部类,但是我想大部分人在开发中都很少使用内部类编写代码。大部人也不知道内部类有什么作用。
接下来,我们就一起来聊聊内部类。
Java中有四种内部类:
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类
public class OutClass{
private class InnerClass{
}
}
特点:
-
直接在外部类中编写内部类,该内部类看起来好像是和外部类的字段方法平级的,其实并不然,因为在编译代码的时候,会将内部类单独编译成一个文件,其中文件名以$标识;
-
成员内部类允许使用private,protected,默认,public所有的权限修饰符修饰;
-
成员内部类的创建必须要依赖于外部类的实例;
-
成员内部类可以随意的访问成员外部类的成员变量。
静态内部类
public class OutClass{
public static InnerClass{
}
}
特点:
-
静态内部类以static关键字修饰;
-
静态内部类允许使用private,protected,默认,public所有的权限修饰符修饰;
-
静态内部类的创建不需要依赖外部类的实例,可以直接通过外部类进行创建;
-
静态内部类只能访问外部类的静态字段和静态方法。
局部内部类
public class OutClass{
public void method(){
class InnerClass{
}
}
}
特点:
-
局部内部类是在外部类方法的外部的方法内;
-
局部内部类不允许任何修饰符进行修饰(因为局部内部类所在的方法上已经有权限了,所有没有必要再局部内部类再设置权限);
-
局部内部类只能在该方法中实例化,不能通过外部实例化;
-
局部内部类和该方法的生命周期不一致;
-
局部内部类如果要访问该方法的局部变量,那么局部变量必须设置为final类型 。访问外部类的变量不必设置为final。
匿名内部类
public interface Iinner{
void say();
}
public class OutClass{
public void sayMethod(){
new Iinner() {
@Override
public void say() {
System.out.println("hello");
}
}.say();
}
}
特点:
-
匿名内部类只能被调用一次;
-
匿名内部类可以访问外部类的成员变量,并且变量不必用final修饰;
-
匿名内部类可以访问方法的局部变量。
疑问点?
问题:
局部内部类访问方法局部变量,局部变量必须要加final,这是为什么呢?
回答:
首先说一下,因为局部内部类是一个类,实例化后是存放到堆中去了,而方法在它执行完毕后就销毁了,所以局部内部类一般要比方法的生命周期长。
那么问题来了,方法都销毁了,局部变量自然也没有了,如果局部内部类中还需要访问该局部变量,那不完了,找不到啊。所以局部内部类访问的局部变量并不是方法中的那个变量,编译源代码的时候,会将该局部变量拷贝一份放到局部内部类中,因为局部内部类其实也是一个单独的文件。
不过这样又有问题了,你想啊,我们在这里创建了局部内部类,并且操作了局部变量,我们是想操作方法中的局部变量啊!你给我了个副本,这怎么能行?
这样随便我们在内部类怎么折腾,方法中的局部变量都没啥影响啊,而且方法中的变量更改了,也不关局部内部类啥事啊。
为了避免出现这样的数据不统一,所有我们要禁止局部变量进行修改,要保证变量的统一。这其实也是无奈之举啊。不过对于引用型数据,我们仍然是可以修改里面的数据的,因为我们方法中的引用和局部内部类中的引用是一致的,都指向的统一地址。
使用内部类对于我们来说有什么好处呢??
- 我们知道Java只能单继承,使用内部类相当于变相的使我们拥有了多继承的能力;
为什么这么说呢?
因为内部类可以直接操作外部类的变量啊,既然能够操作外部类,那么我们用内部类继承某个类之后,在操作外部类变量,不就相当于外部类直接继承该类了吗?
-
使用内部类可以将类私有化,隐藏内部实现细节,方便以后进行修改内部实现;
-
使用内部类有时可以使我们的实现更加简洁,层次分明,代码优雅。(例如:如果一个类不需要外部调用,也仅仅只会被另一个类调用,那么我们完全可以将该类定义成调用类的内部类啊,这样,还隐藏了内部实现细节,还不用单独创建一个类文件。)