权限修饰符 (Access Modifiers)
权限修饰符用于控制类、成员变量、方法、构造方法和内部类的可访问范围。
一、权限修饰符的分类与作用范围
Java 提供了四种访问权限,范围从严格到宽松:
| 修饰符 | 同一个类中 | 同一个包中其他类 | 不同包子类 | 不同包无关类 |
|---|---|---|---|---|
| private | ✅ | ❌ | ❌ | ❌ |
| 默认 (default) (不写任何修饰符) | ✅ | ✅ | ❌ | ❌ |
| protected | ✅ | ✅ | ✅ | ❌ |
| public | ✅ | ✅ | ✅ | ✅ |
访问范围总结:
-
private:仅本类可访问。
-
默认:本类 + 同包其他类。
-
protected:本类 + 同包其他类 + 不同包的子类。
-
public:所有位置都可访问。
二、权限修饰符的使用规则(最佳实践)
-
成员变量通常私有化:
java
public class Student { private String name; // 成员变量私有 private int age; }- 原因:保护数据,防止外部直接修改,通过公有方法进行控制。
-
方法通常公开:
java
public class Student { private String name; // 公开的getter/setter方法 public String getName() { return name; } public void setName(String name) { this.name = name; } // 公开的业务方法 public void study() { System.out.println(name + "正在学习"); } } -
特殊情况:
- 私有方法 :如果某个方法只是为类内部其他方法提供辅助功能(抽取的共性代码),应该设置为
private。
java
public class Calculator { public int add(int a, int b) { validateInput(a, b); return a + b; } public int multiply(int a, int b) { validateInput(a, b); return a * b; } // 私有方法:内部辅助方法,不需要对外公开 private void validateInput(int a, int b) { if (a < 0 || b < 0) { throw new IllegalArgumentException("参数不能为负数"); } } } - 私有方法 :如果某个方法只是为类内部其他方法提供辅助功能(抽取的共性代码),应该设置为
代码块 (Code Blocks)
代码块是使用 {} 括起来的代码段,根据定义位置和关键字的不同,分为以下几种:
一、局部代码块
-
位置:方法内部
-
作用:限定变量生命周期,及早释放内存(现代JVM优化已使其作用不明显)
-
特点:执行时机与普通语句相同
java
public void demo() {
// 普通代码
int x = 10;
System.out.println(x);
// 局部代码块
{
int y = 20; // y的作用域仅限于此代码块内
System.out.println(y);
}
// System.out.println(y); // 编译错误!y已超出作用域
System.out.println(x); // x仍然有效
}
二、构造代码块(实例代码块)
-
位置:类中方法外,成员位置
-
格式 :直接使用
{} -
特点:
-
每次创建对象时都会执行
-
先于构造方法执行
-
用于提取多个构造方法的公共代码
-
java
public class Person {
private String name;
// 构造代码块
{
System.out.println("构造代码块执行:初始化公共部分");
// 这里可以放所有构造方法都需要执行的代码
}
// 无参构造
public Person() {
System.out.println("无参构造执行");
}
// 有参构造
public Person(String name) {
this.name = name;
System.out.println("有参构造执行");
}
}
// 测试
public class Test {
public static void main(String[] args) {
Person p1 = new Person();
// 输出:
// 构造代码块执行:初始化公共部分
// 无参构造执行
Person p2 = new Person("张三");
// 输出:
// 构造代码块执行:初始化公共部分
// 有参构造执行
}
}
三、静态代码块
-
位置:类中方法外,成员位置
-
格式 :
static {} -
特点:
-
随着类的加载而执行(只执行一次)
-
先于构造代码块和构造方法执行
-
用于初始化静态变量或执行只需一次的初始化操作
-
java
public class DatabaseUtil {
// 静态变量
private static String driver;
private static String url;
// 静态代码块:类加载时执行,只执行一次
static {
System.out.println("静态代码块执行:加载数据库配置");
driver = "com.mysql.jdbc.Driver";
url = "jdbc:mysql://localhost:3306/test";
// 这里可以进行复杂的初始化,如读取配置文件
}
// 构造代码块
{
System.out.println("构造代码块执行");
}
public DatabaseUtil() {
System.out.println("构造方法执行");
}
public static void connect() {
System.out.println("使用配置连接数据库...");
}
}
// 测试
public class Test {
public static void main(String[] args) {
// 第一次使用类,触发静态代码块
DatabaseUtil.connect();
// 输出:
// 静态代码块执行:加载数据库配置
// 使用配置连接数据库...
// 创建对象,触发构造代码块和构造方法
DatabaseUtil util1 = new DatabaseUtil();
// 输出:
// 构造代码块执行
// 构造方法执行
// 再次创建对象,静态代码块不会再次执行
DatabaseUtil util2 = new DatabaseUtil();
// 输出:
// 构造代码块执行
// 构造方法执行
}
}
四、代码块执行顺序总结
java
public class Example {
// 静态变量
private static String staticField = "静态变量";
// 静态代码块
static {
System.out.println("1. 静态代码块执行");
}
// 实例变量
private String instanceField = "实例变量";
// 构造代码块
{
System.out.println("3. 构造代码块执行");
}
// 构造方法
public Example() {
System.out.println("4. 构造方法执行");
}
}
// 测试
public class Test {
static {
System.out.println("Test类的静态代码块");
}
public static void main(String[] args) {
System.out.println("开始创建对象...");
Example e = new Example();
// 输出顺序:
// Test类的静态代码块(先加载Test类)
// 开始创建对象...
// 1. 静态代码块执行(加载Example类)
// 3. 构造代码块执行
// 4. 构造方法执行
// 注意:静态变量和实例变量的初始化在实际执行中可能更早
}
}
执行顺序原则:
-
父类静态代码块 → 子类静态代码块(继承时)
-
父类构造代码块 → 父类构造方法
-
子类构造代码块 → 子类构造方法
五、实际应用场景
-
静态代码块:
-
加载数据库驱动:
Class.forName("com.mysql.jdbc.Driver"); -
读取配置文件
-
初始化静态工具
-
-
构造代码块:
-
多个构造方法的公共初始化逻辑
-
对象创建前的统一检查或设置
-
-
局部代码块:
- 临时限制变量作用域(较少使用)