内部类多而繁杂,互访情况下,不管是内访外,还是外访内,静态(类,方法,成员变量)与非静态(类,方法,成员变量)之间的访问也错综复杂。还有各种令人头疼的编译问题,匿名内部类使用的形参为何必须为final修饰等都是面试喜欢问的点。如果您对内部类还有疑惑,读完本文,说不定能让面试官膜拜您。
本文将从内部类的种类,命名规则,匿名内部类编译,内外互访等角度来阐述。
内部类分为4种:
成员内部类
与成员变量类似,写在类里。如果内部类持有外部类的引用,可能导致内部类没有执行完,外部类也无法释放,有内存泄漏风险。想要避免这种现象,需要在外部类对象生命周期结束时手动将内部类对象生命周期结束。除非延迟回收会成为系统的运维瓶颈,一般不需要特别关注,GC机制通常足以应付。
public class Outter {
String s;
class Inner{
}
}
局部内部类
局部内部类是定义在一个方法或者一个作用域里的类。Inner2和Inner都是Outter的内部类。
public class Outter {
public Inner getInner2(){
class Inner2 extends Inner{
String s = "Inner2";
}
return new Inner2();
}
}
class Inner{
String s;
}
静态内部类
好吧,就是成员内部类前面加了static。声明为static的类不会持有外部类的引用,可以通过软引用的方式保存外部类的了引用,只有静态内部类不可能造成内存泄漏。
public class Outter {
String s;
static class Inner{
}
}
匿名内部类
匿名内部类应该是我们用得最多的,在编写事件监听的代码时使用匿名内部类不但方便,而且使代码更加容易维护。
public class Outter {
void test() {
new Thread(new Runnable(){
String S;
@Override
public void run(){}
}).start();
}
}
非匿名内部类类名规则为 OutClass$InnerClass(外部类类名与内部类类名用$连接) 匿名内部类类名则为OutClass$数字(OutClass$1,OutClass$2,OutClass$3)
public class A {
C c = new C(){
String s="i am c";
@Override
public void demo() {
}
};
C c2 = new C(){
String s="i am c2";
@Override
public void demo() {
}
};
}
interface C{
public void demo();
}
先看如下代码:
public class Test {
public void test(final int b) {
final int a = 10;
new Thread(){
public void run() {
System.out.println(a);
}
}.start();
}
}
里面的可以自由访问外面的,访问非静态成员变量时必须先创建对象。
以下从内部类的状态开始阐述。
1.非静态内部类的非静态方法
直接访问
public class Outter {
int i = 5;
static String word = "Hello";
class Inner {
void Test() {
System.out.println(i);
System.out.println(word);
}
}
}
2.非静态内部类的静态方法
非静态内部类不能有静态方法,编译报错。
3.静态内部类的非静态方法
访问非静态成员变量必须先new外部类。
public class Outter {
int i = 5;
static String word = "Hello";
static class Inner {
void Test() {
System.out.println(new Outter().i);
System.out.println(word);
}
}
}
4.静态内部类的静态方法
和第三种情况类似,静态方法访问外部类非静态成员变量必须先new外部类。
public class Outter {
int i = 5;
static String word = "Hello";
static class Inner {
static void Test() {
System.out.println(new Outter().i);
System.out.println(word);
}
}
}
可以将内部类理解为外部类的一个普通成员,所以外面的访问里面的需先new一个对象。
Outter.Inner inner = new Outter.Inner();
1.非静态方法访问非静态内部类成员
先new内部类
public class Outter {
void Test() {
System.out.println(new Inner().i);
}
class Inner {
int i = 5;
// static String word = "hello"; 编译报错!
}
}
2.非静态方法访问静态内部类的成员
先new内部类,再访问非静态的成员变量
静态成员变量可外部类.内部类.变量名直接访问
public class Outter {
void Test() {
Outter.Inner inner = new Outter.Inner();
System.out.println(inner.i);
System.out.println(inner.string);
System.out.println(Outter.Inner.string);
}
static class Inner {
int i = 5;
static String string = "Hello";
}
}
3.静态方法访问非静态内部类的成员
public class Outter {
static void Test() {
System.out.println(new Outter().new Inner().i);
}
class Inner {
int i = 5;
// static String word = "Hello"; 编译报错!
}
}
4.静态方法访问静态内部类的成员
访问非静态成员需先new 内部类
new Inner().i
与第2种情况相似
public class Outter {
static void Test() {
Outter.Inner inner = new Outter.Inner();
System.out.println(new Inner().i);
System.out.println(inner.i);
System.out.println(Outter.Inner.word);
}
static class Inner {
int i = 5;
static String word = "Hello";
}
}
5.匿名内部类
匿名内部类访问外部成员变量时,成员变量前应加final关键字。
至此,内部类完结,感觉身体被掏空~
博主常年在线,如有疑问或错误,欢迎评论指出
如果喜欢我的文章,欢迎关注知乎专栏Java修仙道路~
参考博文【Java】内部类与外部类的互访使用小结,匿名内部类 类名规则 定位$1