0 简介
Java内部类包括四种:成员内部类、局部内部类、匿名内部类和静态内部类。
1 成员内部类
- 成员内部类位于另一个类的内部,其可以无条件访问外部类的所有成员属性和成员方法(包括private成员和static成员)。
class Outer {
private double a = 0;
public static int b = 1;
public Outer(double a) {
this.a = a;
}
class Inner { //内部类
public void fun() {
System.out.println(a);
System.out.println(b);
}
}
}
- 当成员内部类拥有和外部类同名的成员变量或方法时,默认访问的是成员内部类的成员,如果要访问外部类的同名成员,需要以如下形式进行访问:外部类.this.成员变量;
- 在外部类中如果要访问成员内部类的成员,必须先创建一个成员内部类的对象,再通过指向这个对象的引用来访问;
- 成员内部类是依附外部类而存在的,如果要创建成员内部类的对象,前提是必须存在一个外部类的对象。创建成员内部类对象的一般方式如下:
class Outer {
private double a = 0;
public static int b = 1;
public Outer() {}
public Outer(double a) {
this.a = a;
Inner inner = new Inner();
inner.fun(); //调用内部类的方法
}
class Inner { //内部类
int b = 2;
public void fun() {
System.out.println(a);
System.out.println(b); //访问内部类的b
System.out.println(Outer.this.b); //访问外部类的b
}
}
}
public class Main {
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); //创建内部类的对象
inner.fun();
}
}
0.0
2
1
2 局部内部类
局部内部类是定义在一个方法或者一个作用域里的类,它和成员内部类的区别在于局部内部类的访问权限仅限于该方法内或该作用域内。定义在实例方法中的局部类可以访问外部类的所有变量和方法,定义在静态方法中的局部类只能访问外部类的静态变量和方法。
class Outer {
private int outer_a = 1;
private static int static_b = 2;
public void test1() {
int inner_c = 3;
class Inner {
private void fun() {
System.out.println(outer_a);
System.out.println(static_b);
System.out.println(inner_c);
}
}
Inner inner = new Inner(); //创建局部内部类
inner.fun();
}
public static void test2() {
int inner_d = 3;
class Inner {
private void fun() {
System.out.println(outter_a); //编译错误,定义在静态方法中的局部类不可以访问呢外部类的实例变量
System.out.println(static_b);
System.out.println(inner_d);
}
}
Inner inner = new Inner();
inner.fun();
}
}
3 匿名内部类
匿名内部类指没有名字的内部类,使用匿名内部类的前提条件:必须继承一个父类或实现一个接口。
interface Person {
public void fun();
}
class Demo {
public static void main(String[] args) {
new Person() {
public void fun() {
System.out.println("hello world");
}
}.fun();
}
}
4 静态内部类
静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个static关键字。静态内部类不需要依赖于外部类,并且它不能使用外部类的非static成员变量或方法。
class Outer {
int a = 1;
static int b = 2;
public Outer() {}
static class Inner {
public Inner() {
System.out.println(a); //报错,静态内部类不能访问非静态变量
System.out.println(b);
}
}
}
public class Main {
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner(); //创建内部类的对象
}
}
5 内部类的优点
- 内部类不为同一包的其他类所见,具有很好的封装性;
- 匿名内部类可以很方便地定义回调;
- 每个内部类都能独立继承一个接口的实现,所以无论外部类是否已经继承了某个(接口)的实现,对于内部类都没有影响;
- 内部类有效实现了”多重继承“,优化了Java单继承的缺陷;
6 局部内部类和匿名内部类访问局部变量时,为什么变量必须加上final?
public class Main {
public static void main(String[] args) {
}
public void fun(final int b) {
final int a = 10;
new Thread() {
public void run() {
System.out.println(a);
System.out.println(b);
};
}.start();
}
}
- 对于变量a可以从生命周期的角度理解,局部变量直接存储在栈中,当方法执行结束后,非final的局部变量就被销毁,而局部内部类对局部变量的引用依然存在,如果局部内部类要调用没有final修饰的局部变量时,就会造成生命周期不一致出错;
- 对于变量b,其实是将fun方法中的变量b以参数的形式对匿名内部类中的拷贝(变量b的拷贝)进行赋值初始化。在run方法中访问的变量b根本就不是test方法中的局部变量b,而是一个拷贝值,所以不存在生命周期不一致的问题,但如果在run方法中修改变量b的值会导致数据不一致,所以需要加final修饰。