一,前言
在 Java 中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类。广泛意义上的内部类一般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。
作用:
1,间接性实现Java多继承,每个内部类都能独立的继承一个接口的实现,因此对于外部类来说就算继承了某个父类,在内部类中是不会有任何影响的。
2,可以将复杂的逻辑代码组合在一起,且对外是隐藏的。
3,内部多线程的使用。
二,成员内部类
成员内部类是最普通的内部类,它的定义为位于另一个类的内部。
访问规则:
1,内部类可以不受权限符的限制,直接访问外部类的成员变量。
2,实例化内部类之前,必须先创建外部类对象,才能访问内部类属性。
直接创建内部类公式为:
外部类名称.内部类名称 对象名 = new 外部类名称.new 内部类名称();
3,外部类不能直接访问内部类的变量和方法,需要通过内部类对象进行访问。
public class Outer {
private Inner inner = null;
int num = 10;
public Inner getInner() {
if (inner == null)
inner = new Inner();
return inner;
}
public class Inner {
int num = 20;
public void heart() {
int num = 30;
System.out.println("就近原则:" + num); // 结果:30
System.out.println("本类中;" + this.num); // 结果:20
System.out.println("外部类中:" + Outer.this.num); // 结果:10
}
}
}
成员内部类是最为普通的一种,但上述代码有个细节就是在外部类中,内部类及内部类方法中存在变量名称相同的问题。在这种情况下访问规则是:
1,就近原则,先访问本方法中的变量值。
2,如果访问本类中可使用this关键字。
3,如果访问外部类变量值(方法),使用方式为:外部类名称.this.变量名称(外部类.this.成员方法)。
创建方法有两种:
//第一种方式:直接创建
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); //必须通过Outer对象来创建
inner.heart();
//第二种方式:间接创建
Outer.Inner inner1 = outer.getInner();
inner1.heart();
三,局部内部类
如果一个类是定义在方法内部的,那就是一个局部内部类。
"局部":出了这个方法,其他地方都不能调用局部内部类。
public class LocalCLass {
public void localInner(){
// 局部内部类
class Inner{
int num = 10;
public void methodInner(){
System.out.println("局部内部类:"+num); // 结果:10
}
}
// 在方法内部,调用局部内部类
Inner inner = new Inner();
inner.methodInner();
}
}
注意:
1,关于类的权限修饰符:
public>protected>(default)>private
外部类:public/(default)
内部类:public/protected/(default)/private
局部内部类:什么都不能写
2,局部类访问局部成员方法:
- 如果要访问这个局部类所在方法的局部变量,那么必须是有效的final修饰的。
- 从jdk8+开始,只要局部变量实际上不会改变,则可以省略final关键字。
为什么要被final关键字修饰,这个和对象的生命周期有关系。
1,new出来的对象是在内存的堆中的。
2,局部变量是跟着方法走的,在栈内存中。
3,当方法结束后,便会即可出栈,局部变量消失。
4,而new出来的对象还在堆内存中,直到GC回收消失。
因此,当局部内部类还在堆内存中时,如果再次使用局部变量时,而方法中的局部变量已经出栈消失了。因此必须使用final修饰为常量,使局部内部类可以去常量池中复制一份。另一个原因就是,如果不是final修饰为常量,后期该局部变量值被修改了,那么便会造成局部内部类读取的数据不一致的情况。
四,匿名内部类
匿名内部类简单理解就是没有类名称的类。
一般在实际开发中匿名类是使用最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
那么一般在什么情况下会使用到匿名内部类。
如果接口的实现类(父类的子类)只需要唯一的一次。那么这种情况下就可以省略对该类的实现,直接使用匿名内部类。
请看如下代码,先来定义一个接口。
public interface IAnonymous {
void anonymousMethod();
}
// 匿名内部类的创建方式
// 第一种方法
IAnonymous anonymous = new IAnonymous() {
@Override
public void anonymousMethod() {
System.out.println("使用匿名内部类实现接口!");
}
};
anonymous.anonymousMethod();
// 第二种方式,匿名对象
new IAnonymous(){
@Override
public void anonymousMethod() {
System.out.println("使用匿名对象实现接口!");
}
}.anonymousMethod();
匿名内部类注意事项:
1,匿名内部类在创建对象的时候,只能使用唯一的一次,如果要多次创建同一个对象时,
并且内容是相同的,那必须单独定义实现类或者子类。
2,匿名对象,在调用方法的时候,只能调用唯一的一次。如果同一个对象要调用多个方法,
则需要给对象定义对象名称。
3,匿名内部类是省略了实现类或者子类,而匿名对象是省略了对象名称。两者并不是一回事。
五,静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使用外部类的非static成员变量或者方法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
public class StaticInnerClass {
// 外部类静态成员属性
private static int num = 10;
public static class staticInner{
public void staticMethod(){
System.out.println("静态内部类!");
System.out.println("外部静态成员变量:"+num);
}
}
}
class StaticMain{
public static void main(String[] args) {
StaticInnerClass.staticInner innerClass = new StaticInnerClass.staticInner();
innerClass.staticMethod();
}
}
六,总结
每种内部类均有各自的使用场景,因此对于内部类的使用也要根据自己的业务需求进行选择。尤其也要注意内部类使用的细节问题,以及使用规则。
最后以上均是自主学习总结,如有不适之处还请留言指教。
感谢阅读!