一、代码块
- 代码块是类的五大成分之一(成员变量、构造器、方法、代码块、内部类)
1.分类
- 静态代码块(非必须,优化用)
java
static{}
类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
- 实例代码块
java
{}
每次创建对象时执行,执行实例代码块,并在构造器之前执行
2.应用场景
- 静态代码块 :核心作用是一次性初始化类级别的静态资源,并非笼统的 "优化用"。 常见场景:加载配置文件、注册数据库驱动、初始化静态集合 / 全局常量。 注意:静态代码块中只能直接访问静态成员,不能直接访问实例成员
- 实例代码块 :核心价值是提取多个构造器的公共初始化逻辑,减少代码重复。 比如你的聊天室窗口有多个构造器,每个都要初始化消息面板、输入框,就可以把初始化逻辑放进实例代码块,所有构造器执行前都会自动运行。 注意:实例代码块可以访问类的所有成员(静态 + 实例)
二、内部类(innerclass)
1.成员内部类
java
//定义
public class A{
public class a{}//定义在外部类里面
}
//调用
A.a a1=new A().new a();//通过外部类创建内部类,寄生在外部类对象上
- 成员内部类可以访问外部类的静态实例成员和实例方法
- 在成员内部类的实例方法中,可以直接拿到外部类的对象:外部类.this
- 成员内部类归属于外部类对象
- 静态成员限制 :成员内部类中不能定义普通静态变量和静态方法 (唯一例外:
static final静态常量)。因为成员内部类依附于外部类对象,而静态成员属于类层级,语义冲突 - 当内部类变量、外部类成员变量、方法局部变量重名时,通过不同语法区分
java
public class A {
int num = 10; // 外部类成员变量
public class Inner {
int num = 20; // 内部类成员变量
public void test() {
int num = 30; // 方法局部变量
System.out.println(num); // 30 → 局部变量
System.out.println(this.num); // 20 → 内部类成员
System.out.println(A.this.num);// 10 → 外部类成员
}
}
}
2.静态内部类
java
//定义
public class A{
public static classa{}
}
//调用
A.a a1=new A.a();
- 静态内部类只能拿到外部类静态资源,如果要访问外部类的实例成员,必须手动 new 外部类对象
- 静态内部类归属于外部类本身
- 典型应用 :JDK 集合中大量使用,比如 HashMap 的
Node节点类、ArrayList 的迭代器,都是静态内部类 ------ 不需要持有外部类对象的引用,既节省内存,也更符合语义
3.局部内部类(了解)
java
public class A{
public void go(){
class a{}
}
}
定义在方法内部的类,没什么意义,补全语法完整性,只有特殊的局部内部类才有用(匿名内部类)
- 不能加任何访问修饰符(
private/public/static都不行),和方法内的局部变量地位一致。 - 作用域极窄:仅在定义它的方法 / 代码块内可见,出了方法就无法使用。
- 变量捕获规则 :局部内部类访问方法内的局部变量时,变量必须是
final或 "事实上的 final(effectively final)",赋值后不能再修改引用 ------ 和 Lambda 表达式规则完全一致。
4.匿名内部类(重点)
- 是一种特殊的局部内部类
- 所谓匿名:指的是程序员不需要为这个类声明名字,默认有个隐藏的名字
- 其本质上是一个子类,是一种更便捷的创建子类的写法
- 如果是继承类、或者接口有多个抽象方法,只能用匿名内部类,不能用 Lambda
- 编译项目后看到带
$的 class 文件,就是内部类编译生成的
java
new 类/接口(参数值){
类体(一般是方法重写);
}
开发中常见形式
- 通常作为一个对象参数传输给方法使用