内部类共分四种:成员内部类、静态成员内部类、局部内部类、匿名内部类
(下面先说成员内部类、静态成员内部类、局部内部类,最后单独说匿名内部类)
(上面这三句注释是理解这三种内部类的核心)
new一个成员内部类:
在Outer类的外部,为了找到这个内部类,需要在这个内部类类名前加上外部类的类名。即Outer.Inner(若在Outer类内部使用,则不需要加Outer点),可以将成员内部类当成是成员变量,将new成员内部类当作是访问这个“成员变量”的构造函数。要访问一个类的成员变量,则首先需要new一个这个类的对象(即new Outer()),然后用这个对象去调用这个“成员变量”的构造函数(即new Outer().new Inner())。
new一个静态成员内部类:
在Outer类的外部,为了找到这个内部类,需要在这个内部类类名前加上外部类的类名。即Outer.NestedClass(若在Outer类内部使用,则不需要加Outer点),可以将成员静态内部类当成是静态成员变量,将new静态成员内部类当作是访问这个“静态成员变量”的构造函数。要访问一个类的静态成员变量,可以直接用类名去访问不用new对象,所以直接new Outer.NestedClass()
new一个局部内部类:
如同局部变量只在方法内部有效,局部内部类也只在方法内部能使用。
访问特性:
·成员内部类和局部内部类中可以直接访问到外部类的所有成员变量以及方法(包括私有)。
·静态成员内部类只能访问到外部类的静态成员变量以及方法(很好理解,静态成员内部类的创建不依赖于外部类的对象,即可以不用new外部类就可以使用静态成员内部类,那么如果没有new外部类,则外部类的非静态成员变量以及方法也就不存在,那你这个静态成员内部类中怎么能访问到呢?)
内部类的修饰符:
对于成员内部类以及静态成员内部类来说,它们就相当于外部类的成员变量,所以任何能修饰成员变量的都能修饰它们(public,private,static,final)。若被private修饰则该内部类只能在外部类的内部使用而不能在外部类的外部使用,道理同成员变量的访问权限。
(类其实只能被public,final,abstract三种修饰符修饰,而不能被private,static修饰,可见内部类其实本质上被当成了变量而不是类)
对于局部内部类来说,它就相当于局部变量,不存在用public或private或static去修饰一个局部变量,所以也不存在用它们来修饰局部内部类。
对于局部内部类的注意事项:
局部内部类中若要访问方法中的局部变量,则所访问的局部变量必须是声明了final的常量(即局部内部类不能够访问局部变量,只能访问局部常量)
原因是,局部变量是位于栈中的,如上面的i,而new出来的东西是在堆中的,如local。栈的回收机制是,方法执行结束,则栈清空,即上面的method方法执行完后,i就被回收了。而堆的回收机制是靠Java的自动回收机制,即在method执行完后,i立即被回收了,而local并不会被立马回收。则local的method方法,将会访问一个不存在的变量,造成风险,所以不被编译器所允许。
而若访问的是局部常量,则编译器会直接将System.out.println(i)变成System.out.println(100),从而就没有前面说的问题了。
而jdk1.8后,若局部内部类访问了局部变量,则编译器会自动帮我们在那个局部变量前加上final,使其变为常量,所以上面代码中不加final也是可以的,但是我们得清楚,实际上在局部内部类中所有的i都会被替换成常量。
匿名内部类(本质是没有名字的局部内部类):
(不使用匿名内部类) (使用匿名内部类)
匿名内部类用于快捷实现接口或抽象类或快捷对普通类进行继承覆写