在上一篇博文 【内部类】JAVA 中的四大内部类【上】 中,有介绍到内部类、成员内部类,只说了四大内部类中的其中一个。接下来,此文就来介绍剩下的三种内部类:局部内部类、静态内部类、匿名内部类
2.2 局部内部类
什么是局部内部类?
局部内部类相当于一个局部变量,在一个方法中/局部代码块中定义一个类,称为局部内部类(不能被 public、private 修饰)
那局部内部类和成员内部类的区别就显而易见了 ------ 它们所处的位置不同。
定义、构建局部内部类
public class OuterClass {
public void getInnerClass() {
// 定义局部内部类(不能被 public、private 修饰)
class InnerClass {
public InnerClass() {
}
public InnerClass getInnerClass() {
return this;
}
}
// 只能在局部内部类作用域中 new 一个局部内部类对象
InnerClass innerClass = new InnerClass();
}
}
当然,也可以在 if 代码块中定义局部内部类:
public class OuterClass {
public void getInnerClass() {
// 定义局部内部类(不能被 public、private 修饰)
if (true) {
class InnerClassTwo {
public InnerClassTwo() {
}
public InnerClassTwo getInnerClass() {
return this;
}
}
}
}
}
全部代码:
public class OuterClass {
public void getInnerClass() {
// 定义局部内部类(不能被 public、private 修饰)
class InnerClass {
public InnerClass() {
System.out.println("外部类对象引用:" + OuterClass.this);
}
public InnerClass getInnerClass() {
return this;
}
}
InnerClass innerClass = new InnerClass();
InnerClass instance = innerClass.getInnerClass();
System.out.println("内部类对象的引用:" + instance);
boolean flag = true;
if (flag) {
class InnerClassTwo {
public InnerClassTwo() {
System.out.println("外部类对象引用:" + OuterClass.this);
}
public InnerClassTwo getInnerClass() {
return this;
}
}
InnerClassTwo innerClassTwo = new InnerClassTwo();
InnerClassTwo instanceTwo = innerClassTwo.getInnerClass();
System.out.println("内部类对象的引用:" + instanceTwo);
flag = false;
}
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
outerClass.getInnerClass();
}
}
运行代码知:这两个局部内部类的外部类引用是一样的,但各自的内部类对象的引用是不一样的
局部内部类与 final 关键字
局部内部类不能更改局部内部类之外的局部变量的值,否则,会在 IDE 会报错,报错提示为:Variable ‘num’ is accessed from within inner class, needs to be final or effectively final
。如:
public class OuterClass {
public void getInnerClass() {
int num = 0;
class InnerClass {
public InnerClass() {}
public InnerClass getInnerClass() {
// 修改局部内部类之外的局部变量,会报错
num++;
return this;
}
}
}
}
由报错提示知:在局部内部类中要使用它之外的局部变量,只能是 final 常量。
那么,为什么会有这个限制呢?
因为局部变量和局部内部类的生命周期不同,所以,编译器就统一要求,如果局部内部类使用了它之外的局部变量,此时,编译器就按 fianl 常量处理。
例如:
先定义一个类,可供局部内部类继承。
public abstract class AbstractTest {
public abstract void test();
}
public class OuterClass {
public AbstractTest getLocalClass() {
// 局部变量
int num = 10;
// 局部内部类
class LocalClass extends AbstractTest{
@Override
public void test() {
num++;
}
}
AbstractTest instance = new LocalClass();
return instance;
}
public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
AbstractTest localClass = outerClass.getLocalClass();
localClass.test();
}
}
如果没有那个限制,这块代码将会这样运行:
1. 创建了一个外部类对象 OuterClass;
2. 外部对象调用一个成员方法 outerClass.getLocalClass()
;
3. 在成员方法中,会在堆中创建内部类对象 LocalClass;
4. 然后,内部类对象将会调用它自己的成员方法 localClass.test()
。在这个方法中,它会使用一个外部类的方法中的局部变量 num 。但这就有一个问题了:这个外部类方法已经执行完毕了,那么,这个方法中的所有的局部变量的生命周期都应该结束,num 也应该被回收。那这个内部类对象按理就无法访问这个 num 了。所以,为了避免上述问题,编译器进行了上述的处理。
2.3 静态内部类
什么是静态内部类?
使用关键字 static 修饰的成员内部类
定义、构建静态内部类
静态内部类不依赖于外部类对象的
public class OuterClass {
private String name;
private static int type = 1;
public static class InnerClass {
public InnerClass() {
// 静态内部类不能访问外部类的费静态成员
System.out.println(type);
}
}
public static void main(String[] args) {
// 构建静态内部类
InnerClass innerClass = new OuterClass.InnerClass();
}
}
静态内部类对象构建规则:new 外部类.静态内部类名();
应用场景
当一个类是另外一个类(外部类)的附属类,它不依赖外部类对象而存在,并且它需要单独在外部类之外的类去使用,此时,就可以定义为静态内部类。
如:
public class User {
private int id;
private String name;
private int age;
}
// 用户查询类
public class UserQuery {
// 查询用户列表 传入查询条件
public List<User> listUsers(QueryParam queryParam) {
return new ArrayList<>();
}
// 用户查询条件类 存放用户查询条件(可以根据 Id、name 查询)
public static class QueryParam {
private int id;
private String name;
}
}
有一个用户信息类 User,现在有一个 UserQuery 类来查询用户信息的,如果根据条件查询的话,还需要给查询方法传入参数。这里将传入的参数封装在了一个内部类类中。
考虑到用户查询条件类 QueryParam 可能不仅用在 UserQuery 类中,还可能用在其它类中,那么,就可以将 QueryParam 类定义为静态内部类
2.4 匿名内部类
什么是匿名内部类?
匿名内部类是一种特殊的局部内部类,它没有名字
定义匿名内部类的规则:
new 父类/接口() {
// TODO
}
略…