当前位置: 首页 > news >正文

Java面试-访问修饰符:public、protected、default、private 详解

请添加图片描述

👋 欢迎阅读《Java面试200问》系列博客!

🚀大家好,我是Jinkxs,一名热爱Java、深耕技术一线的开发者。在准备和参与了数十场Java面试后,我深知面试不仅是对知识的考察,更是对理解深度与表达能力的综合检验。

✨本系列将带你系统梳理Java核心技术中的高频面试题,从源码原理到实际应用,从常见陷阱到大厂真题,每一篇文章都力求深入浅出、图文并茂,帮助你在求职路上少走弯路,稳拿Offer!

🔍今天我们要聊的是:《访问修饰符:public、protected、default、private 详解》。准备好了吗?Let’s go!


🎯 引言:Java 世界的“门禁系统”大揭秘

“在Java的世界里,最像‘小区门禁’的,不是SecurityManager,而是——访问修饰符。”

想象一下你住的小区:

  • public:小区大门,谁都能进(只要不违法)。
  • protected:单元楼门禁,本楼住户和亲戚(子类)能进。
  • default(包访问):家门口,只有你和家人(同包)知道密码。
  • private:卧室门锁,只有你自己(本类)能进。

今天,我们就来扒一扒这四位“门神”的底细,看看它们如何守护Java世界的秩序。


📚 目录导航(别走丢了)

  1. 四大门神登场:public、protected、default、private
  2. public:小区大门,谁都能进
  3. protected:单元楼门禁,本楼住户和亲戚专用
  4. default(包访问):家门口,只有家人知道密码
  5. private:卧室门锁,只有我自己能进
  6. 继承中的访问权限“升级”规则
  7. 内部类的访问权限“特例”
  8. 面试常见陷阱大揭秘
  9. 使用场景总结:什么时候该用哪个?

1. 四大门神登场:public、protected、default、private

Java 提供了四种访问修饰符,用来控制类、方法、变量、构造器等成员的访问权限。

✅ 它们就像不同级别的门禁卡,决定了谁能“看到”和“使用”你的代码。

📊 四大访问修饰符权限对比表

修饰符同类同包子类不同包
private
default(无修饰符)
protected❌(仅子类)
public

💡 记住这张表,你就掌握了Java世界的“门禁地图”。


2. public:小区大门,谁都能进

public 是最开放的访问级别,任何地方都可以访问。

✅ 用法:类、方法、变量、构造器

// public 类:任何包都能访问
public class PublicClass {// public 变量:任何地方都能读写public String name = "张三";// public 方法:任何地方都能调用public void sayHello() {System.out.println("你好,我是 " + name);}// public 构造器:任何地方都能 newpublic PublicClass(String name) {this.name = name;}
}

✅ 跨包访问示例

// com.example.utils 包
package com.example.utils;public class MathUtils {public static int add(int a, int b) {return a + b;}
}// com.example.app 包
package com.example.app;import com.example.utils.MathUtils;public class App {public static void main(String[] args) {// ✅ 可以访问 public 类和方法int sum = MathUtils.add(5, 3);System.out.println("和:" + sum);}
}

public 是工具类、API接口的首选。


❌ 注意:public 类必须与文件名相同

// 文件名:MyClass.java
public class MyClass { } // ✅ 正确// public class YourClass { } // ❌ 编译错误!一个文件只能有一个 public 类,且名字必须匹配

3. protected:单元楼门禁,本楼住户和亲戚专用

protected 允许同包不同包的子类访问。

✅ 用法:方法、变量、构造器(不能修饰类)

// com.example.parent 包
package com.example.parent;public class Parent {protected String familySecret = "祖传秘方";protected void familyMeeting() {System.out.println("召开家族会议,讨论:" + familySecret);}protected Parent() {System.out.println("Parent 构造器被调用");}
}

✅ 同包访问(本楼住户)

// com.example.parent 包
package com.example.parent;public class Neighbor {public void visit() {Parent p = new Parent();p.familySecret = "邻居知道了"; // ✅ 同包,可以访问p.familyMeeting(); // ✅ 同包,可以调用}
}

✅ 不同包子类访问(亲戚)

// com.example.child 包
package com.example.child;import com.example.parent.Parent;public class Child extends Parent {public void revealSecret() {// ✅ 子类,可以访问父类 protected 成员System.out.println("我知道的秘密:" + familySecret);familyMeeting();}
}

❌ 不同包非子类不能访问

// com.example.stranger 包
package com.example.stranger;import com.example.parent.Parent;public class Stranger {public void tryToAccess() {Parent p = new Parent();// p.familySecret = "我想知道"; // ❌ 编译错误!不是子类,也不是同包// p.familyMeeting(); // ❌ 编译错误!}
}

protected 常用于父类希望子类继承的方法或变量。


4. default(包访问):家门口,只有家人知道密码

default没有显式修饰符时的默认访问级别,也叫包私有(package-private)

✅ 用法:类、方法、变量、构造器

// com.example.internal 包
package com.example.internal;// default 类:只能同包访问
class InternalClass {// default 变量:只能同包访问String internalData = "内部数据";// default 方法:只能同包访问void processData() {System.out.println("处理数据:" + internalData);}// default 构造器:只能同包访问InternalClass() {System.out.println("InternalClass 创建");}
}

✅ 同包访问

// com.example.internal 包
package com.example.internal;public class Manager {public void manage() {InternalClass ic = new InternalClass();ic.internalData = "更新数据"; // ✅ 同包,可以访问ic.processData(); // ✅ 同包,可以调用}
}

❌ 不同包不能访问

// com.example.external 包
package com.example.external;import com.example.internal.InternalClass; // ❌ 编译错误!InternalClass 不是 publicpublic class External {public void access() {// InternalClass ic = new InternalClass(); // 即使能导入,也无法访问}
}

default 适合“包内协作”的类,对外隐藏实现细节。


5. private:卧室门锁,只有我自己能进

private 是最严格的访问级别,只有本类内部可以访问。

✅ 用法:方法、变量、构造器、内部类(不能修饰外部类)

public class BankAccount {private String accountNumber; // 账号,私有private double balance = 0.0; // 余额,私有// private 构造器:只能本类或内部类调用private BankAccount(String accountNumber) {this.accountNumber = accountNumber;}// 提供 public 方法来安全访问public void deposit(double amount) {if (amount > 0) {balance += amount;logTransaction("存款", amount); // ✅ 本类内可以调用 private 方法}}public void withdraw(double amount) {if (amount > 0 && amount <= balance) {balance -= amount;logTransaction("取款", amount);}}// private 方法:只在本类内部使用private void logTransaction(String type, double amount) {System.out.println("交易记录:" + type + " " + amount + ",余额:" + balance);}// public 方法获取余额(只读)public double getBalance() {return balance;}
}

✅ 使用场景:封装核心数据和逻辑

public class PasswordManager {private String masterPassword = "123456"; // 主密码,绝不暴露public boolean verifyPassword(String input) {// 在这里进行加密比较等操作return input.equals(masterPassword); // ✅ 本类内可以访问}// ❌ 外部无法直接获取 masterPassword
}

private 是实现封装的关键,保护对象的内部状态。


6. 继承中的访问权限“升级”规则

子类重写父类方法时,访问权限不能更严格,但可以更宽松。

✅ 正确示例:权限升级

class Parent {protected void doWork() {System.out.println("Parent work");}
}class Child extends Parent {@Overridepublic void doWork() {  // ✅ 正确:protected → public(更宽松)System.out.println("Child work");}
}

❌ 错误示例:权限降级

class Parent {public void doWork() {System.out.println("Parent work");}
}class Child extends Parent {@Override// private void doWork() { } // ❌ 编译错误!public → private(更严格)// protected void doWork() { } // ✅ 正确:public → protected(更宽松或相同)
}

✅ 规则:privatepackageprotectedpublic,只能向右或持平,不能向左。


7. 内部类的访问权限“特例”

内部类可以拥有所有四种访问修饰符,而外部类只能是 publicdefault

✅ private 内部类

public class Outer {// private 内部类:只有 Outer 类能访问private class PrivateInner {public void display() {System.out.println("我是私有内部类");}}public void createInner() {PrivateInner inner = new PrivateInner(); // ✅ Outer 类内可以创建inner.display();}
}// 其他类
class Other {public void tryCreate() {// Outer.PrivateInner inner = new Outer().new PrivateInner(); // ❌ 编译错误!}
}

✅ protected 内部类

public class Base {protected class ProtectedInner {public void show() {System.out.println("受保护的内部类");}}
}class Sub extends Base {public void accessInner() {ProtectedInner inner = new ProtectedInner(); // ✅ 子类可以访问inner.show();}
}

✅ public 内部类

public class Container {public class PublicInner {public void info() {System.out.println("公开的内部类");}}
}// 其他类
class Client {public void use() {Container.PublicInner inner = new Container().new PublicInner(); // ✅ 可以访问inner.info();}
}

8. 面试常见陷阱大揭秘

❓ 面试题1:default 和 protected 的区别?

答:

  • default:同包内可访问。
  • protected:同包内可访问,且不同包的子类也可访问
// 包A
package A;
class Parent {String def = "default";protected String pro = "protected";
}// 包B
package B;
import A.Parent;
class Child extends Parent {void test() {// def = "x"; // ❌ default 成员,不同包非同包子类不能访问pro = "y"; // ✅ protected 成员,子类可以访问}
}

❓ 面试题2:private 方法能被继承吗?

不能!
private 方法对子类不可见,子类无法继承,也无法重写。

class Parent {private void secret() { }
}class Child extends Parent {// public void secret() { } // 这不是重写,是一个新方法// Child 类根本不知道 Parent 有个 secret() 方法
}

❓ 面试题3:为什么外部类不能是 private 或 protected?

答:因为外部类需要被其他类导入(import)

  • private:只有本类能访问,外部类无法被导入。
  • protected:只有同包和子类能访问,但子类还没创建,无法导入。

所以外部类只能是 public(任何地方可导入)或 default(同包可导入)。


❓ 面试题4:构造器可以是 private 吗?有什么用?

可以! 常用于:

  1. 单例模式:防止外部 new
  2. 工具类:防止实例化
  3. 构建器模式:配合静态工厂方法
public class Singleton {private static Singleton instance;// private 构造器private Singleton() { }public static Singleton getInstance() {if (instance == null) {instance = new Singleton();}return instance;}
}

❓ 面试题5:protected 变量在子类中可以直接访问吗?

可以!
protected 成员在子类中就像自己的成员一样,可以直接访问。

class Parent {protected String name;
}class Child extends Parent {void introduce() {name = "小明"; // ✅ 直接访问父类 protected 变量System.out.println("我是 " + name);}
}

9. 使用场景总结:什么时候该用哪个?

场景推荐修饰符原因
API 接口、工具类public需要被广泛调用
类的核心数据和敏感逻辑private封装,防止外部破坏
希望子类继承的方法或变量protected给子类扩展空间
包内协作的实现类default对外隐藏,对内开放
单例类的构造器private防止外部创建实例
工具类的方法public static方便调用
内部帮助类privatestatic仅本类使用
需要被不同包子类继承的方法protected跨包继承

✅ 黄金法则:尽可能使用最小的访问权限
private 开始,如果不够用,再逐步放宽,直到 public


📈 附录:访问修饰符速查表

位置privatedefaultprotectedpublic
外部类
内部类
构造器
方法
字段
同包访问
不同包子类访问
不同包非子类访问

💡 记住:private 是你的“卧室”,default 是你的“家”,protected 是你的“家族”,public 是你的“朋友圈”。
管好你的“门”,Java世界才安全!


🎯 总结一下:

本文深入探讨了《访问修饰符:public、protected、default、private 详解》,从原理到实践,解析了面试中常见的考察点和易错陷阱。掌握这些内容,不仅能应对面试官的连环追问,更能提升你在实际开发中的技术判断力。

🔗 下期预告:我们将继续深入Java面试核心,带你解锁《自动装箱与拆箱机制解析》 的关键知识点,记得关注不迷路!

💬 互动时间:你在面试中遇到过类似问题吗?或者对本文内容有疑问?欢迎在评论区留言交流,我会一一回复!

如果你觉得这篇文章对你有帮助,别忘了 点赞 + 收藏 + 转发,让更多小伙伴一起进步!我们下一篇见 👋

http://www.dtcms.com/a/346228.html

相关文章:

  • CAN总线工具学习:DBC解析、设备扫描与报文监控
  • Linux环境搭建FTP协议
  • fdisk工具源码编译生成
  • 记SpringBoot3.x + SpringSecurity6.x的实现
  • 20250822日记
  • 深入理解Java虚拟机:JVM高级特性与最佳实践(第3版)第四章知识点问答(37题)
  • 如何编译botan加密库?
  • 模板商城探秘:DINO-X 定制模板指南(1)
  • Ansys Motor-CAD:概述(EMag、THERM、LAB、MECH)
  • Unreal Engine UActorComponent
  • 豆包 + 蘑兔,破解写歌难题!
  • 普中烧录软件 PZISP,打不开,提示“应用程序无法启动,因为应用程序并行配置不正确.....”
  • 深度学习设计模式:责任链(Chain of Responsibility)模式(例子+业务场景+八股)
  • RFID技术在铸管生产车间AGV小车的使用
  • SQL 复杂连接与嵌套查询的优化之道:从自连接、不等值连接到 CTE 的体系化实践
  • 「数据获取」《中国农村统计年鉴》1985-2024(获取方式看绑定的资源)
  • Python中各种数据类型的常用方法
  • 国产轻量级桌面GIS软件Snaplayers从入门到精通(20)
  • 自定义单线通信协议解析
  • Unreal Engine Simulate Physics
  • MySQL InnoDB记录存储结构深度解析
  • windows 帮我写一个nginx的配置,端口是9999,静态资源的路径是D:\upload
  • 企业架构之微服务应用架构
  • 深入理解底层通信协议和应用层协议的区别
  • Java Stream常见函数与应用案例
  • 大模型应用发展与Agent前沿技术趋势(下)
  • Debezium导致线上PostgreSQL数据库磁盘日志飙升处理方案
  • Unreal Engine ATriggerVolume
  • java 海报、图片合成
  • 蓝牙部分解析和代码建构