每日 Java 面试题分享【第 17 天】
欢迎来到每日 Java 面试题分享栏目!
订阅专栏,不错过每一天的练习
今日分享 3 道面试题目!
评论区复述一遍印象更深刻噢~
目录
- 问题一:Java 中的访问修饰符有哪些?
- 问题二:Java 中静态方法和实例方法的区别是什么?
- 问题三:Java 中 for 循环与 foreach 循环的区别是什么?
问题一:Java 中的访问修饰符有哪些?
在 Java 中,访问修饰符用于控制类、变量、方法和构造方法的可见性范围。以下是 Java 的四种访问修饰符及其作用域,结合代码示例和底层原理进行说明:
访问修饰符分类及作用域
修饰符 | 类内部 | 同包其他类 | 不同包子类 | 不同包非子类 |
---|---|---|---|---|
public | ✔️ | ✔️ | ✔️ | ✔️ |
protected | ✔️ | ✔️ | ✔️ | ❌ |
默认(无修饰符) | ✔️ | ✔️ | ❌ | ❌ |
private | ✔️ | ❌ | ❌ | ❌ |
1. public:全局可见
-
作用范围:所有类均可访问。
-
使用场景:开放 API 方法或常量。
-
代码示例:
public class Logger {public static final String LEVEL = "DEBUG"; // 所有类可访问public void log(String message) { /* 实现 */ } }
-
底层原理:编译时无访问限制检查,JVM 通过符号引用直接访问。
2. protected:继承体系可见
-
作用范围:同包类 + 不同包的子类(需通过继承访问)。
-
关键细节:不同包子类中,只能访问从父类继承的
protected
成员,不能直接访问其他父类实例的成员。 -
代码示例:
// 包 com.example; public class Base {protected void init() { /* 初始化逻辑 */ } }// 包 com.other; public class Sub extends Base {void test() {init(); // ✔️ 允许(继承访问)new Base().init(); // ❌ 编译错误(直接访问其他实例)} }
-
设计意义:支持模板方法模式,允许子类扩展特定步骤。
3. 默认(包级私有):同包可见
-
作用范围:仅限同包内类访问。
-
使用场景:包内工具类或组件间协作。
-
代码示例:
class PackagePrivateUtils { // 默认修饰符static void helper() { /* 包内共享工具方法 */ } }
-
底层原理:编译器在跨包访问时校验类权限,阻止外部包通过全限定名访问。
4. private:类内封闭
-
作用范围:仅限当前类内部。
-
使用场景:封装对象状态或内部工具方法。
-
代码示例:
public class Singleton {private static Singleton instance; // 私有静态变量private Singleton() {} // 私有构造方法public static Singleton getInstance() { /* 提供全局访问点 */ } }
-
反射限制:通过
setAccessible(true)
可突破限制,但违背封装原则。
高级应用与原理
-
类本身的修饰符:
- 顶级类(非内部类)只能用
public
或默认修饰符。 - 内部类可任意使用四种修饰符(如
private static class Node
用于链表实现)。
- 顶级类(非内部类)只能用
-
构造方法的特殊修饰:
public class HttpClient {private HttpClient() {} // 强制通过工厂方法创建实例public static HttpClient create() { return new HttpClient(); } }
-
模块系统(Java 9+):
即使成员是public
,若所在模块未导出对应包,其他模块仍无法访问(强化封装性)。
实战技巧
- 最小权限原则:优先使用最严格的访问级别(如默认 > protected > public)。
- 代码维护性:
private
方法更易重构,public
方法需谨慎设计避免破坏兼容性。 - 测试考量:通过包结构组织测试类,合法访问默认和
protected
成员。
通过合理使用访问修饰符,可以有效控制代码的可见性,提升模块化设计和系统安全性。
问题二:Java 中静态方法和实例方法的区别是什么?
一、核心区别对比表(快速建立知识框架)
维度 | 静态方法 (Static Method) | 实例方法 (Instance Method) |
---|---|---|
归属对象 | 类级别(Class Level) | 对象级别(Object Level) |
内存分配时机 | 类加载时 | 对象实例化时 |
调用方式 | ClassName.method() | object.method() |
隐含引用 | 无 this 引用 | 有 this 引用 |
多态支持 | 静态绑定(编译时确定) | 动态绑定(运行时确定) |
访问权限 | 只能访问静态成员 | 可访问静态 + 实例成员 |
线程安全考量 | 需关注静态变量竞争 | 实例变量隔离更易控制 |
二、底层原理深度解析
-
JVM 内存模型差异
- 静态方法:存储在方法区(JDK8+ 的元空间)的类元数据中
- 实例方法:存储在堆内存的对象实例的方法表中
// 示例:通过javap观察方法调用指令 // 静态方法调用指令:invokestatic // 实例方法调用指令:invokevirtual/invokeinterface
-
方法分派机制
class Parent {static void staticMethod() { System.out.println("Parent static"); }void instanceMethod() { System.out.println("Parent instance"); } }class Child extends Parent {static void staticMethod() { System.out.println("Child static"); }@Override void instanceMethod() { System.out.println("Child instance"); } }public static void main(String[] args) {Parent p = new Child();p.staticMethod(); // 输出"Parent static"(静态方法隐藏)p.instanceMethod(); // 输出"Child instance"(实例方法覆盖) }
三、实战应用场景分析
-
静态方法典型使用场景
-
工具类方法(无状态操作)
public final class StringUtils {private StringUtils() {} // 防止实例化public static boolean isEmpty(String str) { return str == null || str.trim().isEmpty();} }
-
工厂模式
public class ConnectionFactory {public static Connection create() { return DriverManager.getConnection(url); } }
-
-
实例方法核心价值
-
状态封装(对象特有行为)
public class Order {private double amount;public void applyDiscount(double rate) { // 操作实例状态this.amount *= (1 - rate);} }
-
模板方法模式
public abstract class PaymentProcessor {public final void process() { // 实例方法控制流程validate();executePayment();sendNotification();}protected abstract void executePayment(); }
-
四、高频面试深挖点
-
为什么静态方法不能是抽象的?
- 静态方法属于类级别,而抽象方法需要子类实现,存在根本性冲突
- 替代方案:使用工厂模式或策略模式实现类似效果
-
静态方法是否可以被重写?
-
严格说不存在重写(Override),只有隐藏(Hide)
-
示例说明:
class Animal { static void eat() { System.out.println("Animal eating"); } } class Dog extends Animal { static void eat() { System.out.println("Dog eating"); } }Animal myDog = new Dog(); myDog.eat(); // 输出Animal eating(静态方法没有多态性)
-
-
如何选择方法类型?决策树
是否需要访问实例变量? ├── 是 → 必须使用实例方法 └── 否 → 是否与对象状态相关?├── 是 → 仍建议实例方法└── 否 → 考虑静态方法
五、性能优化注意事项
-
内存占用对比
- 静态方法:单份代码存储,无对象关联开销
- 实例方法:每个对象持有方法表指针(HotSpot JVM 优化后实际共享代码)
-
JIT 编译影响
- 高频调用的静态方法更易被内联优化(无虚方法表查找)
-
并发安全黄金法则
public class Counter {private static int count = 0;// 错误示范:静态方法操作静态变量未同步public static void unsafeIncrement() { count++; }// 正确方案:静态同步方法public static synchronized void safeIncrement() { count++; } }
六、设计模式中的典型应用
-
单例模式(静态工厂方法)
public class Singleton {private static final Singleton INSTANCE = new Singleton();private Singleton() {}public static Singleton getInstance() { return INSTANCE; } }
-
策略模式(实例方法多态)
public interface PaymentStrategy {void pay(double amount); // 实例方法实现多态 }public class AlipayStrategy implements PaymentStrategy {@Override public void pay(double amount) { /* 具体实现 */ } }
总结回答模板:
" 静态方法与实例方法的本质区别在于方法归属与状态绑定。静态方法属于类层级,在类加载时初始化,适用于工具类和工厂模式;实例方法绑定对象实例,支持多态和状态操作。在阿里中间件开发中,我们严格遵循:操作对象状态必须用实例方法,全局工具方法用静态方法,并通过 Sonar 代码检测确保规范执行。"
问题三:Java 中 for 循环与 foreach 循环的区别是什么?
一、核心区别对比表(快速建立知识框架)
维度 | 传统 for 循环 (for(int i=0;…) ) | 增强 for 循环 (for(E e: collection) ) |
---|---|---|
语法复杂度 | 显式控制索引/迭代器 | 隐式迭代(语法糖) |
底层实现 | 数组:直接索引访问 集合:可能低效遍历 | 数组:编译为传统 for 集合:迭代器模式 |
代码安全性 | 需手动控制边界 | 自动处理越界 |
集合修改能力 | 可通过索引或迭代器安全删除 | 直接删除会抛 ConcurrentModificationException |
性能差异 | 数组遍历快(CPU 缓存优化) LinkedList 慢 | 数组同传统 for 集合迭代器效率更优 |
调试可见性 | 可直接观察索引值 | 无法直接获取当前索引 |
多维度遍历 | 灵活控制嵌套层级 | 需多层嵌套 |
二、底层原理深度解析
-
字节码层面对比(使用 javap 反编译验证)
// 示例代码 List<String> list = Arrays.asList("a", "b");// 传统for循环(集合遍历) for(int i=0; i<list.size(); i++){String s = list.get(i); }// 增强for循环(集合遍历) for(String s : list){}
反编译关键指令:
- 传统 for 循环:
iload
(加载索引) +aload
(加载集合) +invokeinterface
(调用 get) - 增强 for 循环:
invokeinterface
(获取迭代器) +hasNext()
/next()
循环
- 传统 for 循环:
-
数组遍历优化机制
增强 for 循环在遍历数组时,编译器会优化为传统 for 循环:// 源代码 int[] arr = {1,2,3}; for(int num : arr){}// 编译器优化后等价于 for(int i=0; i<arr.length; i++){int num = arr[i]; }
三、实战场景选择指南
-
优先使用增强 for 循环的场景
- 只读遍历集合/数组
- 代码简洁性要求高
- 需要避免
IndexOutOfBoundsException
// 电商订单状态检查(无需修改集合) for(Order order : orderList){if(order.getStatus() == Status.PAID){sendShippingNotification(order);} }
-
必须使用传统 for 循环的场景
- 需要删除/修改集合元素
- 需要反向遍历
- 需要访问相邻元素
// 安全删除元素(使用迭代器模式) for(Iterator<Item> it = cartItems.iterator(); it.hasNext();){Item item = it.next();if(item.isExpired()){it.remove(); // 安全删除} }
四、性能关键指标对比
数据结构 | 传统 for 循环时间复杂度 | 增强 for 循环时间复杂度 |
---|---|---|
ArrayList | O(1) per access | O(1) via iterator |
LinkedList | O(n) per access | O(1) via iterator |
HashSet | 不可用 | O(1) via iterator |
性能测试数据(百万次遍历):
ArrayList:
- 传统for循环:12ms
- 增强for循环:15ms
- 迭代器遍历:18msLinkedList:
- 传统for循环:4200ms(灾难性性能)
- 增强for循环:28ms
- 迭代器遍历:25ms
五、高频面试深挖点
-
为什么增强 for 循环删除元素会抛异常?
- 迭代器的
modCount
与集合的expectedModCount
不一致触发快速失败机制 - 解决方案:使用迭代器的
remove()
方法
- 迭代器的
-
如何实现自定义集合的增强 for 循环支持?
- 实现
Iterable
接口并返回自定义Iterator
public class CustomCollection<T> implements Iterable<T> {// …其他代码@Overridepublic Iterator<T> iterator() {return new CustomIterator();} }
- 实现
-
JDK9 对增强 for 循环的优化
- 引入
ImmutableCollections
的优化迭代器 - 对
List.of()
创建的不可变集合进行遍历优化
- 引入
六、设计模式与最佳实践
-
迭代器模式的应用
增强 for 循环是迭代器模式的语法糖实现:// 等价代码解析 for(Iterator<String> it = list.iterator(); it.hasNext();){String s = it.next();// 循环体 }
-
防御性编程技巧
// 遍历时检测集合是否被外部修改 List<String> safeList = Collections.unmodifiableList(rawList); for(String s : safeList){ // 确保遍历过程不被修改process(s); }
总结回答模板:
" 传统 for 循环与增强 for 循环的核心区别在于控制粒度和实现机制。在阿里高并发场景下,我们遵循:对 ArrayList 等随机访问集合优先使用传统 for 循环提升性能;对 LinkedList 等顺序访问集合必须使用增强 for 循环避免性能灾难。同时,在涉及集合修改时,统一使用迭代器删除模式保证线程安全。"
总结
今天的 3 道 Java 面试题,您是否掌握了呢?持续关注我们的每日分享,深入学习 Java 面试的各个细节,快速提升技术能力!如果有任何疑问,欢迎在评论区留言,我们会第一时间解答!
明天见!🎉
相关文章:
每日 Java 面试题分享【第 17 天】
欢迎来到每日 Java 面试题分享栏目! 订阅专栏,不错过每一天的练习 今日分享 3 道面试题目! 评论区复述一遍印象更深刻噢~ 目录 问题一:Java 中的访问修饰符有哪些?问题二:Java 中静态方法和实例方法的区…...

「全网最细 + 实战源码案例」设计模式——桥接模式
核心思想 桥接模式(Bridge Pattern)是一种结构型设计模式,将抽象部分与其实现部分分离,使它们可以独立变化。降低代码耦合度,避免类爆炸,提高代码的可扩展性。 结构 1. Implementation(实现类…...

JavaScript 进阶(上)
作用域 局部作用域 局部作用域分为函数作用域和块作用域。 函数作用域: 在函数内部声明的变量只能在函数内部被访问,外部无法直接访问。 总结: 函数内部声明的变量,在函数外部无法被访问 函数的参数也是函数内部的局部变量 …...

【编译原理实验二】——自动机实验:NFA转DFA并最小化
本篇适用于ZZU的编译原理课程实验二——自动机实验:NFA转DFA并最小化,包含了实验代码和实验报告的内容,读者可根据需要参考完成自己的程序设计。 如果是ZZU的学弟学妹看到这篇,那么恭喜你,你来对地方啦! 如…...
深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据
深入探讨:服务器如何响应前端请求及后端如何查看前端提交的数据 一、服务器如何响应前端请求 前端与后端的交互主要通过 HTTP 协议实现。以下是详细步骤: 1. 前端发起 HTTP 请求 GET 请求:用于从服务器获取数据。POST 请求:用…...
如何利用Docker和.NET Core实现环境一致性、简化依赖管理、快速部署与扩展,同时提高资源利用率、确保安全性和生态系统支持
目录 1. 环境一致性 2. 简化依赖管理 3. 快速部署与扩展 4. 提高资源利用率 5. 确保安全性 6. 生态系统支持 总结 使用 Docker 和 .NET Core 结合,可以有效地实现环境一致性、简化依赖管理、快速部署与扩展,同时提高资源利用率、确保安全性和生态…...
@Inject @Qualifier @Named
Inject Qualifier Named 在依赖注入(DI)中,Inject、Qualifier 和 Named 是用于管理对象创建和绑定的关键注解。以下是它们的用途、依赖配置和代码示例的详细说明: 1. 注解的作用 Inject:标记需要注入的构造函数、字段…...
创建 priority_queue - 进阶(内置类型)c++
内置类型就是 C 提供的数据类型,⽐如 int 、 double 、 long long 等。以 int 类型为例,分 别创建⼤根堆和⼩根堆。 这种写法意思是,我要告诉这个优先级队列要建一个什么样的堆,第一个int是要存什么数据类型,vecto…...

2. Java-MarkDown文件解析-工具类
2. Java-MarkDown文件解析-工具类 1. 思路 读取markdown文件的内容,根据markdown的语法进行各个类型语法的解析。引入工具类 commonmark 和 commonmark-ext-gfm-tables进行markdown语法解析。 2. 工具类 pom.xml <!-- commonmark 解析markdown --> <d…...

动态规划DP 最长上升子序列模型 登山(题目分析+C++完整代码)
概览检索 动态规划DP 最长上升子序列模型 登山 原题链接 AcWing 1014. 登山 题目描述 五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个…...
css-设置元素的溢出行为为可见overflow: visible;
1.前言 overflow 属性用于设置当元素的内容溢出其框时如何处理。 2. overflow overflow 属性的一些常见值: 1 visible:默认值。内容不会被剪裁,会溢出元素的框。 2 hidden:内容会被剪裁,不会显示溢出的部分。 3 sc…...

家居EDI:Hom Furniture EDI需求分析
HOM Furniture 是一家成立于1977年的美国家具零售商,总部位于明尼苏达州。公司致力于提供高品质、时尚的家具和家居用品,满足各种家庭和办公需求。HOM Furniture 以广泛的产品线和优质的客户服务在市场上赢得了良好的口碑。公司经营的产品包括卧室、客厅…...

1、开始简单使用rag
文章目录 前言数据存放申请api开始代码安装依赖从文件夹中读取文档文档切块将分割嵌入并存储在向量库中检索部分代码构造用户接口演示提示 整体代码 前言 本章只是简单使用rag的一个示例,为了引出以后的学习,将整个rag的流程串起来 数据存放 一个示例…...

Linux Samba 低版本漏洞(远程控制)复现与剖析
目录 前言 漏洞介绍 漏洞原理 产生条件 漏洞影响 防御措施 复现过程 结语 前言 在网络安全的复杂生态中,系统漏洞的探索与防范始终是保障数字世界安全稳定运行的关键所在。Linux Samba 作为一款在网络共享服务领域应用极为广泛的软件,其低版本中…...

安卓(android)实现注册界面【Android移动开发基础案例教程(第2版)黑马程序员】
一、实验目的(如果代码有错漏,可查看源码) 1.掌握LinearLayout、RelativeLayout、FrameLayout等布局的综合使用。 2.掌握ImageView、TextView、EditText、CheckBox、Button、RadioGroup、RadioButton、ListView、RecyclerView等控件在项目中的…...
【 AI agents】letta:2024年代理堆栈演进(中英文翻译)
The AI agents stack AI 代理堆栈 November 14, 2024 11月 14, 2024原文: The AI agents stack官方教程教程学习笔记: 【memgpt】letta 课程1/2:从头实现一个自我编辑、记忆和多步骤推理的代理Understanding the AI agents landscape 了解 AI 代理环境 Although we see a …...

Java中 instanceof 的用法(详解)
目录 引言 基本语法 基本作用 1. 检查对象是否是指定类的实例 2. 检查对象是否是子类的实例 3. 检查对象是否实现某个接口 4.null 处理 错误分析: 5.综合对比示例 最后总结 注意事项 引言 instanceof 概念在多态中引出,因为在多态发生时&…...

联想拯救者R720笔记本外接显示屏方法,显示屏是2K屏27英寸
晚上23点10分前下单,第二天上午显示屏送到,检查外包装没拆封过。这个屏幕左下方有几个按键,按一按就开屏幕、按一按就关闭屏幕,按一按方便节省时间,也支持阅读等模式。 显示屏是 :AOC 27英寸 2K高清 100Hz…...
【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础
文章目录 1. 前言 本文章基于 RocketMQ 4.9.3 1. 前言 RocketMQ 存储部分系列文章: 【RocketMQ 存储】- RocketMQ存储类 MappedFile 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础 【RocketMQ 存储】- 一文总结 RocketMQ 的存储结构-基础...

S4 HANA明确税金本币和外币之间转换汇率确定(OBC8)
本文主要介绍在S4 HANA OP中明确明确税金本币和外币之间转换汇率确定(OBC8)相关设置。具体请参照如下内容: 明确税金本币和外币之间转换汇率确定(OBC8) 以上配置,我们可以根据不同公司代码所配置的使用不同的汇率来对税金外币和本币之间进行换算。来针对…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...
MySQL 隔离级别:脏读、幻读及不可重复读的原理与示例
一、MySQL 隔离级别 MySQL 提供了四种隔离级别,用于控制事务之间的并发访问以及数据的可见性,不同隔离级别对脏读、幻读、不可重复读这几种并发数据问题有着不同的处理方式,具体如下: 隔离级别脏读不可重复读幻读性能特点及锁机制读未提交(READ UNCOMMITTED)允许出现允许…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词
Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵,其中每行,每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid,其中有多少个 3 3 的 “幻方” 子矩阵&am…...
Java线上CPU飙高问题排查全指南
一、引言 在Java应用的线上运行环境中,CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时,通常会导致应用响应缓慢,甚至服务不可用,严重影响用户体验和业务运行。因此,掌握一套科学有效的CPU飙高问题排查方法&…...

Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
省略号和可变参数模板
本文主要介绍如何展开可变参数的参数包 1.C语言的va_list展开可变参数 #include <iostream> #include <cstdarg>void printNumbers(int count, ...) {// 声明va_list类型的变量va_list args;// 使用va_start将可变参数写入变量argsva_start(args, count);for (in…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
Windows 下端口占用排查与释放全攻略
Windows 下端口占用排查与释放全攻略 在开发和运维过程中,经常会遇到端口被占用的问题(如 8080、3306 等常用端口)。本文将详细介绍如何通过命令行和图形化界面快速定位并释放被占用的端口,帮助你高效解决此类问题。 一、准…...