每日 Java 面试题分享【第 13 天】
欢迎来到每日 Java 面试题分享栏目!
订阅专栏,不错过每一天的练习
今日分享 3 道面试题目!
评论区复述一遍印象更深刻噢~
目录
- 问题一:如何在 Java 中调用外部可执行程序或系统命令?
- 问题二:如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
- 问题三:栈和队列在 Java 中的区别是什么?
问题一:如何在 Java 中调用外部可执行程序或系统命令?
在 Java 中,可以通过 Runtime 类 或 ProcessBuilder 类 调用外部可执行程序或系统命令。以下是两种方法的详细说明和使用示例。
方法 1:使用 Runtime 类
代码示例
public class RuntimeExample {public static void main(String[] args) {try {// 调用系统命令(如 Windows 的 dir 或 Linux 的 ls)Process process = Runtime.getRuntime().exec("ls"); // 替换为需要的命令// 获取命令执行的输出try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}// 等待命令执行完成int exitCode = process.waitFor();System.out.println("退出码:" + exitCode);} catch (Exception e) {e.printStackTrace();}}
}
注意
- 返回的
Process对象:Process表示外部进程,可以用来获取输出流、错误流,并控制进程的生命周期。
- 输出流的读取:
- 如果不读取或关闭进程的输出流,可能会导致进程阻塞。
优点
- 简单直接,代码量少。
缺点
- 不够灵活,难以传递复杂参数或处理多个 I/O。
方法 2:使用 ProcessBuilder 类
代码示例
import java.io.BufferedReader;
import java.io.InputStreamReader;public class ProcessBuilderExample {public static void main(String[] args) {try {// 创建 ProcessBuilderProcessBuilder processBuilder = new ProcessBuilder();// 设置要执行的命令(可带参数)processBuilder.command("ping", "www.google.com");// 合并错误流和标准输出流(可选)processBuilder.redirectErrorStream(true);// 启动进程Process process = processBuilder.start();// 读取进程输出try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {String line;while ((line = reader.readLine()) != null) {System.out.println(line);}}// 等待进程完成并获取退出码int exitCode = process.waitFor();System.out.println("退出码:" + exitCode);} catch (Exception e) {e.printStackTrace();}}
}
优点
- 更灵活:
- 支持设置环境变量:
processBuilder.environment().put("ENV_VAR", "value"); - 支持设置工作目录:
processBuilder.directory(new File("/path/to/dir"));
- 支持设置环境变量:
- 可读性好:链式调用清晰明了。
缺点
- 比
Runtime稍微复杂一点。
两种方法的对比
| 特性 | Runtime | ProcessBuilder |
|---|---|---|
| 使用简单性 | 更简单 | 略复杂 |
| 灵活性 | 较低 | 较高 |
| 支持环境变量设置 | 不支持 | 支持 |
| 合并输出和错误流 | 需要手动实现 | 直接支持(redirectErrorStream) |
| 推荐程度 | 适合简单命令调用 | 更推荐,适合复杂调用场景 |
常见使用场景
-
运行系统命令:
- 例如在 Linux 上执行
ls或在 Windows 上执行dir。 - 使用
ProcessBuilder的command方法可以方便地传递参数。
- 例如在 Linux 上执行
-
调用外部可执行程序:
- 例如运行
.exe文件、Python 脚本、Shell 脚本等。 - 确保路径正确,并且有足够权限执行外部程序。
- 例如运行
-
环境变量控制:
- 使用
ProcessBuilder.environment()可以轻松传递自定义的环境变量。
- 使用
-
读取命令输出:
- 无论是标准输出还是错误输出,Java 都可以捕获并处理。
注意事项
-
路径问题:
- 确保外部命令或可执行程序的路径正确,建议使用绝对路径。
- 如果使用相对路径,请确保工作目录正确设置(
ProcessBuilder.directory())。
-
阻塞问题:
- 如果外部进程产生大量输出,但未被读取,会导致阻塞。
- 建议及时读取或关闭进程的输出和错误流。
-
跨平台性:
- 不同操作系统的命令语法可能不同,编写代码时需注意适配性。
-
权限问题:
- 运行外部程序可能需要特定的权限,特别是在受限的环境(如服务器)中。
扩展
如何执行带空格的命令或参数?
-
使用
ProcessBuilder.command()方法,将每个参数单独传递为列表元素。ProcessBuilder processBuilder = new ProcessBuilder(); processBuilder.command("cmd.exe", "/c", "echo", "Hello World!");
如何处理输入流(标准输入)?
-
使用
Process对象的getOutputStream()方法,向外部进程写入数据。Process process = new ProcessBuilder("cat").start(); try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()))) {writer.write("Hello from Java!");writer.flush(); }
总结
在 Java 中调用外部程序时:
- 简单任务使用
Runtime.getRuntime().exec(); - 复杂任务优先使用
ProcessBuilder,以获得更好的灵活性和控制力。
问题二:如果一个线程在 Java 中被两次调用 start() 方法,会发生什么?
问题分析
在 Java 中,Thread 类的 start() 方法被用来启动一个新线程。如果尝试对同一个线程对象调用两次 start() 方法,会发生异常。
答案
如果对同一个线程对象调用两次 start() 方法,第二次调用会抛出 IllegalThreadStateException 异常。这是因为线程一旦启动后,其状态会从 NEW(新建) 转变为其他状态(如 RUNNABLE、TERMINATED 等)。根据 Java 线程模型,已经启动过的线程对象不能被重新启动。
代码示例
public class ThreadStartExample {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程正在运行…");});// 第一次启动线程thread.start();// 再次调用 start() 方法try {thread.start(); // 这里会抛出 IllegalThreadStateException} catch (IllegalThreadStateException e) {System.out.println("异常信息:线程已经启动过,不能再次调用 start()");}}
}
运行结果
线程正在运行…
异常信息:线程已经启动过,不能再次调用 start()
原因分析
1. 线程生命周期
线程的生命周期如下:
NEW:线程对象被创建,但未调用start()。RUNNABLE:调用start()后,线程处于可运行状态。TERMINATED:线程运行完毕,进入终止状态。
当线程离开 NEW 状态后,不能回到 NEW,因此无法再次启动。
2. start() 方法的作用
start() 方法的核心功能是:
- 通知 JVM 创建一个新的线程(底层通过本地方法调用操作系统线程)。
- 将线程状态从
NEW改为RUNNABLE,并让线程进入可调度队列。
第二次调用 start() 时,由于线程不再是 NEW 状态,JVM 会拒绝这个操作,抛出异常。
3. 设计初衷
Java 线程模型的设计目的是让每个 Thread 对象只启动一次,避免复杂的状态管理(如重新初始化线程)。如果需要再次启动线程,应该创建一个新的 Thread 实例。
扩展讲解
如何避免这种问题?
-
检查线程状态:如果需要对线程进行管理,可以通过
Thread.getState()方法检查其状态。示例代码:
public class ThreadStateCheck {public static void main(String[] args) {Thread thread = new Thread(() -> {System.out.println("线程运行中…");});System.out.println("线程状态:" + thread.getState()); // NEWthread.start();System.out.println("线程状态:" + thread.getState()); // RUNNABLE 或 TERMINATEDtry {thread.start(); // 再次调用会抛异常} catch (IllegalThreadStateException e) {System.out.println("异常:线程已经启动过");}} } -
重新创建线程对象:如果需要重复执行任务,可以通过新建线程实现:
Thread thread1 = new Thread(() -> System.out.println("任务 1")); thread1.start();Thread thread2 = new Thread(() -> System.out.println("任务 2")); thread2.start();
线程池的使用
如果需要多次执行相同任务,推荐使用线程池(ExecutorService),而非手动管理 Thread 对象。例如:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class ThreadPoolExample {public static void main(String[] args) {ExecutorService executor = Executors.newFixedThreadPool(2);Runnable task = () -> System.out.println("任务正在运行…");executor.execute(task); // 启动任务executor.execute(task); // 再次启动任务executor.shutdown();}
}
线程池可以高效管理线程复用,避免直接操作线程带来的复杂性。
总结
- 对一个线程对象调用两次
start()方法会抛出IllegalThreadStateException。 - 每个线程对象只能启动一次。如果需要重新运行任务,需要新建线程实例或使用线程池。
- 推荐使用线程池(如
ExecutorService)来管理多次任务执行,避免手动控制线程的复杂性。
问题三:栈和队列在 Java 中的区别是什么?
栈和队列的区别
栈(Stack)和队列(Queue)是两种常用的线性数据结构,它们在数据存取方式和应用场景上有显著的区别。以下从定义、操作规则、实现和应用等方面进行分析:
1. 栈 (Stack)
定义
栈是一种**后进先出(LIFO, Last In First Out)**的数据结构,即最后插入的数据最先被取出。
核心操作
push(E item):将元素压入栈顶。pop():移除并返回栈顶元素。peek():仅返回栈顶元素,但不移除。
Java 实现
-
使用
java.util.Stack类。 -
示例代码:
import java.util.Stack;public class StackExample {public static void main(String[] args) {Stack<Integer> stack = new Stack<>();stack.push(10);stack.push(20);stack.push(30);System.out.println("栈顶元素:" + stack.peek()); // 输出 30System.out.println("弹出元素:" + stack.pop()); // 输出 30System.out.println("弹出后栈顶:" + stack.peek()); // 输出 20} }
2. 队列 (Queue)
定义
队列是一种**先进先出(FIFO, First In First Out)**的数据结构,即最先插入的数据最先被取出。
核心操作
add(E item)或offer(E item):将元素添加到队列尾部。remove()或poll():移除并返回队列头部元素。element()或peek():仅返回队列头部元素,但不移除。
Java 实现
-
使用
java.util.Queue接口的实现类,例如LinkedList或ArrayDeque。 -
示例代码:
import java.util.LinkedList; import java.util.Queue;public class QueueExample {public static void main(String[] args) {Queue<Integer> queue = new LinkedList<>();queue.offer(10);queue.offer(20);queue.offer(30);System.out.println("队列头元素:" + queue.peek()); // 输出 10System.out.println("移除元素:" + queue.poll()); // 输出 10System.out.println("移除后队列头:" + queue.peek()); // 输出 20} }
3. 栈与队列的主要区别
| 特性 | 栈 (Stack) | 队列 (Queue) |
|---|---|---|
| 访问规则 | 后进先出(LIFO) | 先进先出(FIFO) |
| 常用方法 | push()、pop()、peek() | offer()、poll()、peek() |
| 插入位置 | 栈顶 | 队尾 |
| 移除位置 | 栈顶 | 队头 |
| 实现方式 | 使用 java.util.Stack | 使用 java.util.Queue 接口及实现类 |
| 常见应用场景 | 递归、括号匹配、函数调用栈、回溯算法 | 消息队列、任务调度、广度优先搜索 |
4. 特殊队列:双端队列 (Deque)
定义
双端队列(Deque, Double-Ended Queue)允许在队首和队尾同时插入和移除元素。
实现
-
使用
java.util.ArrayDeque或java.util.LinkedList。 -
示例代码:
import java.util.Deque; import java.util.ArrayDeque;public class DequeExample {public static void main(String[] args) {Deque<Integer> deque = new ArrayDeque<>();deque.addFirst(10); // 插入到队首deque.addLast(20); // 插入到队尾System.out.println("队首元素:" + deque.peekFirst()); // 输出 10System.out.println("队尾元素:" + deque.peekLast()); // 输出 20deque.removeFirst(); // 移除队首deque.removeLast(); // 移除队尾} }
应用
- 双端队列可用于实现栈或队列的功能,也可以用作滑动窗口算法等高级场景。
5. 实际应用场景
- 栈:
- 函数调用栈
- 括号匹配
- 表达式求值
- 深度优先搜索(DFS)
- 队列:
- 任务调度
- 广度优先搜索(BFS)
- 消息队列
- 缓冲区管理
总结
- 栈是后进先出的数据结构,常用于递归、回溯等场景。
- 队列是先进先出的数据结构,适合任务调度和广度优先搜索等场景。
- 双端队列是栈和队列的通用化版本,既可以实现栈的功能,也可以实现队列的功能。
总结
今天的 3 道 Java 面试题,您是否掌握了呢?持续关注我们的每日分享,深入学习 Java 面试的各个细节,快速提升技术能力!如果有任何疑问,欢迎在评论区留言,我们会第一时间解答!
明天见!🎉
相关文章:
每日 Java 面试题分享【第 13 天】
欢迎来到每日 Java 面试题分享栏目! 订阅专栏,不错过每一天的练习 今日分享 3 道面试题目! 评论区复述一遍印象更深刻噢~ 目录 问题一:如何在 Java 中调用外部可执行程序或系统命令?问题二:如果一个线程…...
探究 Facebook 隐私安全发展方向,未来走向何方?
随着社交媒体的普及,隐私和数据安全问题成为了全球关注的焦点。Facebook,作为全球最大的社交平台之一,其隐私安全问题尤其引人注目。近年来,随着用户数据泄露事件的不断发生,Facebook 不断调整其隐私政策,探…...
第三十一周学习周报
目录 摘要Abstract文献阅读总体架构实验分析 知识复习总结 摘要 在本周阅读的文献中,作者提出了一种基于生成对抗网络(GAN)和长短期记忆网络(LSTM)融合模型的连续管钻井参数预测方法,旨在提高连续管钻井的…...
白嫖一个可以公网访问、带评论和图床的博客系统
这里我来把搭建这个网站的过程记录下,可供新手朋友搭建 完成github page的创建 首先先打开github官网,然后打开your repositories这个标签 然后新建一个repositories,名字是比较特殊的,为<username>.github.io这个格式&am…...
定时器、计数器
定时器:TON TOF TONR:保持型接通定时器 TP:脉冲定时器:触发一次,就开始计时 TP:按下I0.1 TP开始计时,Q电开始有电,时间到Q点失电 计数器:CTU加 CTD减 CTUD加减 两个方法…...
Ubuntu Server连接wifi
背景 家里服务器放在客厅太吵了, 准备挪到阳台, 所以买了TP wifi接收器, 因此需要配置wifi连接. 刚开始买了Tenda Ax300, 结果不支持服务器系统, 买前还是得和客服交流交流. 准备 驱动安装 对于windows系统来说, 这款接收器是免驱的, 但在linux上需要安装相应型号驱动 安装…...
关于MySQL InnoDB存储引擎的一些认识
文章目录 一、存储引擎1.MySQL中执行一条SQL语句的过程是怎样的?1.1 MySQL的存储引擎有哪些?1.2 MyIsam和InnoDB有什么区别? 2.MySQL表的结构是什么?2.1 行结构是什么样呢?2.1.1 NULL列表?2.1.2 char和varc…...
深入剖析SpringBoot启动机制:run()方法详尽解读
摘要 本文深入解析SpringBoot的启动机制,以run()方法为核心,逐步追踪并详细解释其关键步骤。首先探讨run()方法的工作原理,然后深入代码层面分析各个关键环节。文章提供刷新后钩子和启动后任务的代码示例,帮助读者理解SpringBoot源…...
Nginx中部署多个前端项目
1,准备前端项目 tlias系统的前端资源 外卖项目的前端资源 2,nginx里面的html文件夹中新建,tlias和sky两个文件夹。 切记这是在nginx/html下创建的 mkdir sky mkdir tlias 把tlias和sky的资源都放到对应的文件夹中 3,编辑配置ngi…...
1688寻源通:赋能跨境贸易的高效业务平台
前言 在全球化的浪潮下,跨境电商已成为推动经济发展的重要力量。作为国内领先的B2B电商平台,1688凭借其强大的供应链资源和创新技术,推出了“寻源通”业务,旨在帮助国内供应商和跨境采购商实现更高效、更精准的供需匹配ÿ…...
JVM深入学习(一)
目录 一.JVM概述 1.1 为什么要学jvm? 1.2 jvm的作用 1.3 jvm内部构造 二.JVM类加载 2.1类加载过程 2.2类加载器 2.3类加载器的分类 2.4双亲委派机制 三.运行时数据区 堆空间区域划分(堆) 为什么分区(代)?(…...
Qt Creator 15.0.0如何更换主题和字体
1.打开Qt Creator 15.0.0 (Community), 2.点击编辑栏3.点击Preferences... 4.修改主题,点击环境,修改Theme:栏 5.修改字体大小,点击文本编辑器,修改字号栏。,修改Theme:栏...
“大模型横扫千军”背后的大数据挖掘--浅谈MapReduce
文章目录 O 背景知识1 数据挖掘2 邦费罗尼原则3 TF.IDF4 哈希函数5 分布式文件系统 一、MapReduce基本介绍1. Map 任务2. 按键分组3. Reduce 任务4. 节点失效处理5.小测验:在一个大型语料库上有100个map任务和若干reduce任务: 二、基于MapReduce的基本运…...
shallowRef和shallowReactive的用法以及使用场景和ref和reactive的区别
Vue3 浅层响应式 API 1. ref vs shallowRef 1.1 基本概念 ref: 深层响应式,会递归地将对象的所有属性转换为响应式shallowRef: 浅层响应式,只有 .value 的改变会触发更新,不会递归转换对象的属性 1.2 使用对比 // ref 示例 const deepRe…...
maven、npm、pip、yum官方镜像修改文档
文章目录 Maven阿里云网易华为腾讯云 Npm淘宝腾讯云 pip清华源阿里中科大华科 Yum 由于各博客繁杂,本文旨在记录各常见镜像官网,及其配置文档。常用镜像及配置可评论后加入 Maven 阿里云 官方文档 setting.xml <mirror><id>aliyunmaven&l…...
HTML5+SVG+CSS3实现雪中点亮的圣诞树动画效果源码
源码介绍 这是一款基于HTML5SVGCSS3实现雪中点亮的圣诞树动画效果源码。画面中的圣诞树矗立在雪地中,天上飘落着雪花。当鼠标滑过圣诞树时,可见到圣诞树上的灯光闪烁,同时左下角探出雪怪模样的半个脑袋,四处张望着。整体画面栩栩…...
HTML-新浪新闻-实现标题-样式1
用css进行样式控制 css引入方式: --行内样式:写在标签的style属性中(不推荐) --内嵌样式:写在style标签中(可以写在页面任何位置,但通常约定写在head标签中) --外联样式…...
Linux-day10
第21章 Linux高级篇-日志管理 日志介绍和实例 基本介绍 系统常用的日志 日志服务 日志服务原理图 在这个配置文件里面记录了日志服务程序 日志管理服务rsyslogd -v是反向匹配 invert 日志服务配置文件 时间、主机、是由哪个程序或者服务发生的、事件信息 自定义日志服务 日…...
【Unity3D】《跳舞的线》游戏的方块单方向拉伸实现案例
通过网盘分享的文件:CubeMoveMusic.unitypackage 链接: https://pan.baidu.com/s/1Rq-HH4H9qzVNtpQ84WXyUA?pwda7xn 提取码: a7xn 运行游戏点击空格动态创建拉伸的方块,由Speed控制速度,新方向是随机上下左右生成。 using System.Collect…...
AI智能日志分析系统
文章目录 1.combinations-intelligent-analysis-starter1.目录结构2.pom.xml3.自动配置1.IntelligentAnalysisAutoConfiguration.java2.spring.factories 2.combinations-intelligent-analysis-starter-demo1.目录结构2.pom.xml3.application.yml4.IntelligentAnalysisApplicat…...
C++_核心编程_多态案例二-制作饮品
#include <iostream> #include <string> using namespace std;/*制作饮品的大致流程为:煮水 - 冲泡 - 倒入杯中 - 加入辅料 利用多态技术实现本案例,提供抽象制作饮品基类,提供子类制作咖啡和茶叶*//*基类*/ class AbstractDr…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
【C++特殊工具与技术】优化内存分配(一):C++中的内存分配
目录 一、C 内存的基本概念 1.1 内存的物理与逻辑结构 1.2 C 程序的内存区域划分 二、栈内存分配 2.1 栈内存的特点 2.2 栈内存分配示例 三、堆内存分配 3.1 new和delete操作符 4.2 内存泄漏与悬空指针问题 4.3 new和delete的重载 四、智能指针…...
LLaMA-Factory 微调 Qwen2-VL 进行人脸情感识别(二)
在上一篇文章中,我们详细介绍了如何使用LLaMA-Factory框架对Qwen2-VL大模型进行微调,以实现人脸情感识别的功能。本篇文章将聚焦于微调完成后,如何调用这个模型进行人脸情感识别的具体代码实现,包括详细的步骤和注释。 模型调用步骤 环境准备:确保安装了必要的Python库。…...
32单片机——基本定时器
STM32F103有众多的定时器,其中包括2个基本定时器(TIM6和TIM7)、4个通用定时器(TIM2~TIM5)、2个高级控制定时器(TIM1和TIM8),这些定时器彼此完全独立,不共享任何资源 1、定…...
