目录
[1. 核心定义](#1. 核心定义)
[2. 权限范围速查表(必考核心)](#2. 权限范围速查表(必考核心))
[3. 单个修饰符精准定义](#3. 单个修饰符精准定义)
[4. 设计思想](#4. 设计思想)
[二、底层实现原理(含 JDK 源码分析 / 反编译验证)](#二、底层实现原理(含 JDK 源码分析 / 反编译验证))
[1. 双重校验机制(底层本质)](#1. 双重校验机制(底层本质))
[2. 字节码底层标记](#2. 字节码底层标记)
[3. 反编译验证](#3. 反编译验证)
[4. 继承与权限底层规则](#4. 继承与权限底层规则)
[5. JDK 源码典范(String 类)](#5. JDK 源码典范(String 类))
[1. 基础用法:本类内访问(全权限生效)](#1. 基础用法:本类内访问(全权限生效))
[2. 跨包 / 子类访问测试(验证权限)](#2. 跨包 / 子类访问测试(验证权限))
[坑点 1:误以为 default 跨包子类可访问](#坑点 1:误以为 default 跨包子类可访问)
[坑点 2:误以为 protected 不同包任意类可访问](#坑点 2:误以为 protected 不同包任意类可访问)
[坑点 3:子类重写方法缩小访问权限](#坑点 3:子类重写方法缩小访问权限)
[坑点 4:滥用 public 修饰成员变量](#坑点 4:滥用 public 修饰成员变量)
[坑点 5:混淆 private 和继承](#坑点 5:混淆 private 和继承)
[坑点 6:类用 private/protected 修饰](#坑点 6:类用 private/protected 修饰)
[1. 4 种访问修饰符的权限排序与范围?](#1. 4 种访问修饰符的权限排序与范围?)
[2. protected 和 default 的核心区别?](#2. protected 和 default 的核心区别?)
[3. 为什么成员变量推荐用 private?](#3. 为什么成员变量推荐用 private?)
[4. 子类重写方法的访问权限规则?](#4. 子类重写方法的访问权限规则?)
[5. 外部类可以用 private 修饰吗?](#5. 外部类可以用 private 修饰吗?)
[6. 访问修饰符的本质作用?](#6. 访问修饰符的本质作用?)
[六、项目改造 / 落地记录](#六、项目改造 / 落地记录)
[1. 改造前(错误用法,企业严禁)](#1. 改造前(错误用法,企业严禁))
[2. 改造后(企业标准实践)](#2. 改造后(企业标准实践))
[3. 改造落地好处](#3. 改造落地好处)
一、核心定义与设计思想
1. 核心定义
Java 提供 4 种访问修饰符 ,用于控制类、成员变量、成员方法、构造方法 的访问权限,权限从小到大排序 :private → default(包访问权限,无关键字)→ protected → public
2. 权限范围速查表(必考核心)
| 修饰符 | 本类内部 | 同包类 | 不同包子类 | 不同包任意类 |
|---|---|---|---|---|
private |
✅ | ❌ | ❌ | ❌ |
default |
✅ | ✅ | ❌ | ❌ |
protected |
✅ | ✅ | ✅ | ❌ |
public |
✅ | ✅ | ✅ | ✅ |
3. 单个修饰符精准定义
- private(私有) :仅限当前类内部访问,封装的核心手段;
- default(默认 / 包私有) :无关键字,仅限当前类 + 同包类访问;
- protected(受保护) :仅限当前类 + 同包类 + 不同包子类访问;
- public(公共) :全项目任意位置均可访问,最高权限。
4. 设计思想
- 信息隐藏:隐藏内部实现细节,禁止外部非法访问;
- 封装保障 :是 Java 封装特性的底层技术支撑;
- 代码安全:控制核心数据 / 方法的访问范围,避免误修改;
- 模块化解耦:限定模块间的访问边界,降低代码耦合度。
二、底层实现原理(含 JDK 源码分析 / 反编译验证)
1. 双重校验机制(底层本质)
访问控制的实现依赖 编译器 + JVM 运行期 双重强制校验:
- 编译期校验:编译器直接拦截非法访问,代码无法编译;
- 运行期校验:JVM 加载类时,校验字节码中的访问标记,拒绝非法调用。
2. 字节码底层标记
Java 编译器会为每个成员生成访问标志位,存储在字节码中,JVM 以此判断权限:
ACC_PUBLIC:0x0001ACC_PRIVATE:0x0002ACC_PROTECTED:0x0004ACC_ABSTRACT:0x0400
3. 反编译验证
测试代码:
java
public class Test {
private int a;
protected int b;
public int c;
int d; // default
}
反编译命令:javap -v Test核心字节码标记:
java
private int a; // ACC_PRIVATE
protected int b; // ACC_PROTECTED
public int c; // ACC_PUBLIC
int d; // ACC_DEFAULT(无标记)
结论:修饰符直接编译为字节码标记,JVM 严格按标记校验权限。
4. 继承与权限底层规则
子类重写父类方法时,访问权限只能放大 / 保持不变,不能缩小:
- 父类
public→ 子类只能public - 父类
protected→ 子类可protected/public - 父类
default→ 子类可default/public - 父类
private→ 子类无法重写
5. JDK 源码典范(String 类)
java
public final class String {
// private:核心数据私有化,外部无法访问
private final char value[];
// public:对外暴露公共方法
public int length() { return value.length; }
}
三、代码示例
1. 基础用法:本类内访问(全权限生效)
java
public class Person {
private String name; // 私有
int age; // 默认
protected String gender;// 受保护
public String id; // 公共
// 本类内部:4种修饰符均可直接访问
public void show() {
name = "张三";
age = 20;
gender = "男";
id = "1001";
}
}
2. 跨包 / 子类访问测试(验证权限)
父类(包 1:com.demo)
java
package com.demo;
public class Parent {
private int a = 1;
int b = 2; // default
protected int c = 3;
public int d = 4;
}
子类(包 2:com.test)
java
package com.test;
import com.demo.Parent;
// 不同包子类
public class Child extends Parent {
public void test() {
// a++; 报错:private 不可访问
// b++; 报错:default 不同包不可访问
c++; // 正常:protected 不同包子类可访问
d++; // 正常:public 全范围可访问
}
}
不同包非子类
java
package com.test;
import com.demo.Parent;
// 不同包、无继承关系
public class Test {
public void test() {
Parent p = new Parent();
// p.c; 报错:protected 不同包非子类不可访问
p.d; // 正常:仅public可访问
}
}
四、高频踩坑点与避坑方案
坑点 1:误以为 default 跨包子类可访问
- 问题:不同包的子类,无法访问父类的
default成员; - 避坑:子类跨包访问 → 必须用
protected/public。
坑点 2:误以为 protected 不同包任意类可访问
- 问题:
protected仅限子类,不同包非子类无法访问; - 避坑:全项目访问 → 用
public。
坑点 3:子类重写方法缩小访问权限
- 问题:父类
public方法,子类写protected,编译报错; - 避坑:重写方法权限 只放大、不缩小。
坑点 4:滥用 public 修饰成员变量
- 问题:破坏封装,外部可随意修改核心数据;
- 避坑:成员变量必须用
private,方法用public暴露。
坑点 5:混淆 private 和继承
- 问题:父类
private成员,子类无法继承 / 访问; - 避坑:私有成员是类独有,和继承无关。
坑点 6:类用 private/protected 修饰
- 问题:外部类只能用
public/default,编译报错; - 避坑:只有内部类 可以用
private/protected修饰。
五、面试高频考点与标准答案
1. 4 种访问修饰符的权限排序与范围?
标准答案 :权限从小到大:private < default < protected < public;
- private:本类;
- default:本类 + 同包;
- protected:本类 + 同包 + 不同包子类;
- public:全项目。
2. protected 和 default 的核心区别?
标准答案 :default 仅限同包 ;protected 支持不同包子类访问,是继承场景的核心修饰符。
3. 为什么成员变量推荐用 private?
标准答案 :private 是封装的核心,隐藏内部数据,通过 getter/setter 控制访问,保证数据安全与合法性校验。
4. 子类重写方法的访问权限规则?
标准答案 :子类方法的访问权限 不能小于 父类方法,只能放大或保持不变。
5. 外部类可以用 private 修饰吗?
标准答案 :不可以 。外部类仅支持 public/default,private/protected 只能修饰内部类。
6. 访问修饰符的本质作用?
标准答案 :实现信息隐藏和封装,控制代码访问边界,保障程序安全性、可维护性。
六、项目改造 / 落地记录
企业开发黄金规范
- 成员变量 :强制
private(封装底线); - 对外接口 :
public暴露核心方法; - 子类复用 :
protected定义模板方法; - 包内工具 :
default封装包内逻辑; - 禁止 :
public修饰成员变量。
1. 改造前(错误用法,企业严禁)
java
// 1. 成员变量public,破坏封装
// 2. 无权限控制,数据可随意修改
// 3. 子类重写缩小权限,编译报错
public class User {
public String username; // 错误
protected void show(){}
}
public class VipUser extends User {
private void show(){} // 错误:缩小权限
}
2. 改造后(企业标准实践)
java
// 实体类:标准权限规范
public class User {
// 1. 私有成员变量(底线)
private String username;
// 2. 公共getter/setter
public String getUsername() { return username; }
public void setUsername(String username) { this.username = username; }
// 3. 公共业务方法
public void show(){}
// 4. 子类复用:protected
protected void init(){}
}
// 子类:重写方法权限不变/放大
public class VipUser extends User {
@Override
public void show(){} // 权限放大,合法
}
3. 改造落地好处
- 数据安全:私有变量禁止外部修改,避免业务异常;
- 封装规范:符合阿里 Java 开发手册,团队协作统一;
- 扩展性 :
protected支持子类扩展,不破坏核心逻辑; - 可维护性:权限边界清晰,后期迭代无风险。
总结
- 核心权限 :
private(本类) →default(同包) →protected(子类) →public(全局); - 底层本质:编译器 + JVM 双重校验,字节码标记控制访问,是封装的底层支撑;
- 避坑铁律 :成员变量必
private,重写不缩权限,外部类不用private; - 实战规范:私有变量、公共方法、受保护复用、包内默认,企业开发标准准则。