内部类的定义和特点
定义
简单来说, 在一个类里面定义的类就叫做内部类。
如下,在 Outer 里面又定义了一个叫做 Inner 的类,这个 Inner 就叫做内部类,而 Outer 就是外部类。
1 | class Outer { |
特点
- 内部类可以访问外部类的所有成员
- 外部类需要创建内部类的对象才能访问(私有成员也可以访问)
例如:
1 | package com.inner; |
何时使用内部类
现实世界里面,一个事物还包含了另一个事物,那么为它们设计类的时候,就可以使用到内部类。
静态内部类及其使用
定义
在内部类加上 static 修饰符就是静态内部类。如下:
1 | class Outer2 { |
如何直接创建静态内部类对象
- 在内部类非静态的情况下(不是直接创建,用来作对比而已)
1 | package com.inner; |
- 在内部类是静态的情况下
静态内部类体现在可以直接创建其对象,而不是先创建一个外部类的对象。
1 | package com.inner; |
静态内部类中的静态方法
静态内部类中的静态方法,可以直接访问。
1 | package com.inner; |
内部类访问重名变量的特点
如果在外部类中有一个叫做 num 的变量,在内部类中也有一个 num 变量,在内部类的方法里面还有一个 num 变量,那么如何访问到这些同名的变量呢?
答案是:
- 访问方法内的变量:直接访问即可
- 访问内部类中的变量:this.变量名
- 访问外部类中的变量:外部类名.this.变量名
例子:
1 | package com.inner; |
顺便一提,内部类之所以可以访问外部类,是因为内部类持有外部类的引用。
局部内部类
定义
局部内部类就是:在类的方法中定义的类。
例如,在 Outer4 的 method 方法中的 Inner 类就是局部内部类。
1 | class Outer4 { |
特点
在局部内部类中,只能访问外部类中用 final 修饰的变量。
1 | class Outer4 { |
原因是: 如果 method 方法中定义了一个 Inner 内部类,那么这个类可以将这个内部类的对象返回(可以用 Object 接收)。问题是,将这个对象返回了,可是 method 方法也出栈了,method 的局部变量都释放了,Inner 类中使用的变量不存在,就会出错了。如果使用的变量被 final 修饰了,比如
1 | final int num = 6; |
那么出现 num 的地方,实际上使用的是 6 。这样就不存在使用的变量被释放的情况了。
Java8 的特性
下面的代码是可以运行的。
1 | class Outer4 { |
可以看成在 Java8 中,默认给我们加了 final 。前提是这个变量没有被修改。
如果这个变量被修改了,那么就不会默认地加上 final。
1 | class Outer4 { |
从编译器的角度看,你的方法中有个变量,你只是在局部内部类中访问了一下,那么我就帮你个忙,替你把 final 几个字加上去,反正这个变量不需要更改。但是,如果这个变量你还要改动的,那我就不能给你加上 finnal 了,加了你就不能改了,我只能提醒你,你的代码有问题了。
匿名内部类
定义
匿名内部类它也是内部类,所以它还是在一个类里面定义的。
其次,它是匿名的,也就是没有名字的。
它没有名字,那怎么创建这个类的对象呢?只能用它爹的名字了。
所以,匿名内部类的一个要求就是,必须继承某个类,或者实现某个接口。(别忘了,任何一个类都是继承自 Object 类的。)
使用
- 通过它爹的名字,来创建一个匿名内部类。这个类与它爹不同,因为这个类可以覆盖它爹的方法,或者定义新的方法。创建一个匿名内部类之后,就可以直接调用里面的方法了。不过这样只能调用一个方法,要调用另一个的话,只能再创建另一个匿名内部类了,所以,可以采用第二种方式。
1 | class Outer5 { |
- 创建了一个匿名内部类之后,将这个对象的保存起来。这样就可以,创建一次对象,调用多次方法。
1 | class Outer5 { |
需要注意的是:通过父类引用,只能调用父类中声明的方法。