今天看到一篇很好的讲java内部类的文章,决定再总结下java的内部类。

傻逼百度居然搜不到。。。

 

内部类分类?

1)静态内部类,static关键字修饰;

2)非静态内部类;

非静态内部类又可以进一步分为方法内部类,类内部类和匿名内部类三种。

 

作用或者说为什么需要内部类?

个人觉得只有两点:

1)封装。我现在写了一个主类A,又需要定义一个辅助类或者数据类B,且B仅仅被A使用,那么这种情况完全没有必要把B定义在外面,因为其他类不会用到。也就是说一个类如果仅仅被另一个类使用,就应该定义为内部类,算是实现细节,应该隐藏。并且,非静态内部类天然可以访问外部类的属性。

2)黑科技。利用内部类实现一些技术,比方说多继承,单例等等。

 

静态vs非静态?

首先说下二者区别,除了语法上的,在使用上的区别主要是:

非静态内部类实例化必须依附于一个外部类对象;而静态内部类的实例则是独立的,也就是说静态内部类除了做了隐藏在使用上与其他类没有区别(指内部使用)。

使用场景:

这个在另一篇文章有讲,简而言之就是,看内部类实例是否一定依附于外部类。

​https://stackoverflow.com/questions/253492/static-nested-class-in-java-why​

 

原理?

编译带有内部类的类,会生成多个类,比如:

public class Data {

private long id;

public void f(){
int local = 10;
new Runnable(){

@Override
public void run() {
System.out.println(local);
}
};
}

public class Inner{
public void g(){
System.out.println(id);
}
}

public static class AAA{

}
}

javac编译后有三个class文件:

Data$1.class:

package com.liyao;

class Data$1 implements Runnable {
Data$1(Data var1, int var2) {
this.this$0 = var1;
this.val$local = var2;
}

public void run() {
System.out.println(this.val$local);
}
}

Data$AAA.class:

package com.liyao;

public class Data$AAA {
public Data$AAA() {
}
}

Data$Inner.class:

package com.liyao;

public class Data$Inner {
public Data$Inner(Data var1) {
this.this$0 = var1;
}

public void g() {
System.out.println(Data.access$000(this.this$0));
}
}

以及Data.class

可以看到,非静态内部类的构造方法都多了一个外部类的实例入参,这也是为什么非静态内部类必须依附一个外部实例以及可以很方便访问外部类属性的原因。非静态内部类的字节码其实就和普通类没有太大区别。

 

匿名内部类或者lamda表达式引用外部局部变量为什么必须final?

通过上面的例子可以看到,其实这个变量也是通过内部类的构造函数入参传进来的,所以其实是一个值传递。一旦值已被传入,那么这个值就无法再被外界改变了,即使修改局部变量也不会再影响内部类获取到的值。为了让程序员消除可以通过修改外部变量而影响到内部类的取值的错误想法,索性就规定这里必须final的(当然java8不用final,但是不能改)。