some java面试题
在Java中,Exception
(异常)和Error
(错误)都是继承自Throwable
类的子类,它们用于指示程序中发生了某种不正常的情况。尽管它们有一些相似之处,但它们代表了不同类型的事件,并且通常需要以不同的方式进行处理。
Exception(异常)
- 定义:
Exception
及其子类表示由程序或外部环境导致的条件,这些条件是可以被程序捕获并处理的。 - 特性:
- 可以被捕获并通过适当的异常处理机制进行处理。
- 通常表明程序遇到了一种可以恢复的情形。
- 分为检查性异常(checked exceptions)和非检查性异常(unchecked exceptions)。检查性异常要求必须在代码中显式地处理或者声明抛出,例如
IOException
;非检查性异常则不需要强制处理,通常是编程错误的结果,比如NullPointerException
。
Error(错误)
- 定义:
Error
及其子类表示严重的问题,通常是不可恢复的,这类问题大多数是由JVM抛出的,用来指示一些不应该出现的严重情况。 - 特性:
- 不建议也不应该尝试捕获错误,因为它们通常意味着程序无法继续安全运行。
- 表示系统级的问题,如内存溢出、链接失败等,这些问题通常超出了应用程序的控制范围。
- 常见的例子包括
OutOfMemoryError
、StackOverflowError
等。
总结
- 处理方式:对于
Exception
,我们通常可以通过try-catch语句捕获并处理,从而让程序有机会恢复正常执行。而对于Error
,一般情况下不应试图捕获,因为它们往往指示着非常严重的问题,程序在这种情况下很难或不可能恢复。 - 目的:
Exception
用于指示那些程序设计者认为是正常的可预见的问题,并提供了处理这些问题的机会。而Error
则是为了指出那些严重的、通常是不可恢复的问题,提醒开发者注意并修正潜在的设计或实现缺陷。
在Java中,异常可以分为两大类:检查性异常(Checked Exceptions)和非检查性异常(Unchecked Exceptions)。非检查性异常又通常被称为运行时异常(Runtime Exceptions)。下面详细介绍这三种类型的异常及其区别:
检查性异常(Checked Exceptions)
- 定义:检查性异常是指那些在编译时期就必须处理的异常。它们通常是外部因素导致的异常,例如文件未找到、网络连接失败等。
- 特性:
- 必须在方法签名中使用
throws
关键字声明,或者在方法体内用try-catch
块捕获并处理。 - 表示程序在正常操作过程中可能遇到的可恢复的情况。
- 继承自
Exception
类但不继承自RuntimeException
。 - 常见的例子包括
IOException
、SQLException
等。
- 必须在方法签名中使用
非检查性异常(Unchecked Exceptions)/ 运行时异常(Runtime Exceptions)
- 定义:非检查性异常是指那些在编译时期不需要强制处理的异常,也称为运行时异常。它们通常是由编程错误引起的,比如试图访问空引用的方法或数组越界等。
- 特性:
- 不需要在方法签名中声明,也不强制要求在代码中捕获。
- 表示程序逻辑中的错误,这些错误通常是由于程序员的疏忽造成的。
- 继承自
RuntimeException
类,而RuntimeException
本身是Exception
的一个子类。 - 常见的例子包括
NullPointerException
、ArrayIndexOutOfBoundsException
、ArithmeticException
等。
区别
- 编译器检查:检查性异常在编译阶段会被Java编译器强制要求处理,而非检查性异常则不会。
- 原因:检查性异常通常是由于外部资源不可用等原因造成的,而非检查性异常更多是因为程序内部错误导致的。
- 处理方式:对于检查性异常,你需要决定是否通过
throws
声明将其抛出给调用者处理,还是在当前方法内使用try-catch
来处理。而对于非检查性异常,虽然你也可以选择处理它们,但这不是必须的,并且很多时候你会希望通过改进代码质量来避免这类异常的发生。
thread.sleep(0)有什么作用
在Java中,调用Thread.sleep(0)
意味着请求当前正在执行的线程暂停执行0毫秒,即请求线程放弃剩余的时间片并允许具有相同优先级的其他线程有机会运行。这种技术有时被称为“让出(yield)”,但要注意的是,这与直接调用Thread.yield()
方法的效果并不完全相同。
具体作用
- 调度提示:
Thread.sleep(0)
主要是给线程调度器一个暗示,表示这个线程愿意放弃剩余的时间片。然而,是否真的会有上下文切换取决于底层操作系统的线程调度策略和当前系统负载等因素。 - 促进公平性:在一个多线程环境中,使用
Thread.sleep(0)
可以帮助提高线程间的公平性,尤其是在有多个相同优先级的线程竞争CPU时间时,可以增加其他线程获得执行的机会。 - 不同于
Thread.yield()
:虽然两者的目标相似,都是为了给其他线程提供执行机会,但是它们的行为可能会有所不同。Thread.yield()
是一个本地方法,其行为依赖于具体的JVM实现以及操作系统调度策略。相比之下,Thread.sleep(0)
更明确地依赖于操作系统的线程调度机制来决定是否进行上下文切换。
需要注意的是,使用Thread.sleep(0)
并不能保证任何特定的行为或结果,它只是向调度器发出的一个建议。实际上,是否会发生上下文切换,以及哪个线程将获得执行机会,仍然由操作系统的线程调度算法决定。因此,在大多数情况下,直接依赖这种方法来控制线程的执行顺序并不是最佳实践。对于需要精确控制线程执行的情况,通常推荐使用更高层次的并发控制工具,如锁、信号量或其他同步机制。
ExecutorService.shutdown()
在Java中,Thread
对象本身并没有提供shutdown()
方法。ExecutorService
接口提供的线程池管理功能,特别是当调用其shutdown()
方法后的任务执行行为。
关于 ExecutorService.shutdown()
当你调用一个ExecutorService
的shutdown()
方法时,它会停止接受新的任务提交,但是会继续执行已经提交到服务中的任务。具体的行为如下:
- 拒绝新任务:一旦
shutdown()
被调用,尝试向该ExecutorService
提交新任务将会被拒绝,并抛出RejectedExecutionException
。 - 完成已提交的任务:对于在调用
shutdown()
之前已经提交的任务,包括那些可能还在等待执行的任务,ExecutorService
会继续执行它们直到完成。
如果你希望在调用shutdown()
后立即停止所有正在等待或执行的任务,可以考虑使用shutdownNow()
方法。这个方法会尝试停止所有正在执行的任务,并返回一个列表包含还未开始执行的任务。
示例代码
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(new Task()); // 提交任务A
executor.submit(new Task()); // 提交任务B
executor.shutdown(); // 调用shutdown,此时不能再提交新任务,但A和B将继续执行// 如果你想尝试立即停止所有任务,可以使用:
// List<Runnable> notExecutedTasks = executor.shutdownNow();
在这个例子中,即使调用了shutdown()
,如果任务A和任务B已经被提交,在它们完成之前,ExecutorService
会确保它们得到执行。然而,任何在shutdown()
调用之后尝试提交的新任务都会被拒绝。
请根据你的实际需要选择合适的方法来控制线程池的行为。如果你的目标是优雅地关闭服务并确保所有已提交的任务完成,那么shutdown()
是你想要的方法;如果你需要立即停止所有活动,那么shutdownNow()
将更适合。
springIOC
Spring IOC(Inversion of Control,控制反转)是Spring框架的核心概念之一。它是一种设计思想,通过这种思想,对象的创建和依赖关系的管理从程序代码中转移到了外部容器(如Spring容器)。这种方法使得代码更加解耦、更易于测试和维护。
核心概念
-
Bean: 在Spring中,由Spring IoC容器管理的对象称为Bean。它们是构成应用程序的基本组件。
-
IoC容器: Spring提供了两种类型的IoC容器,分别是
BeanFactory
和ApplicationContext
。ApplicationContext
是BeanFactory
的子接口,提供了更多企业级功能的支持,如AOP特性、消息资源处理、事件发布等。 -
依赖注入(DI): 依赖注入是实现控制反转的一种方式,指的是对象的依赖关系由外部容器在运行时动态地注入到对象内部,而不是由对象自己创建或查找其依赖。
实现依赖注入的方式
-
构造器注入: 通过类的构造函数来注入依赖。
-
Setter方法注入: 使用JavaBean风格的setter方法注入依赖。
-
字段注入: 直接在字段上使用注解进行注入,这种方式虽然简洁但不如前两种方式推荐,因为它不利于单元测试。
配置Bean的方式
-
基于XML配置: 在早期版本的Spring中广泛使用,通过XML文件定义Bean及其依赖关系。
-
基于注解配置: 使用注解(如
@Component
,@Service
,@Repository
,@Controller
等)标注需要被容器管理的类,并使用@Autowired
等注解自动装配依赖。 -
基于Java配置: 使用配置类和
@Configuration
,@Bean
等注解以编程方式定义Bean及其依赖关系。
Spring IoC的优点
- 降低耦合度:通过将对象之间的依赖关系交由容器管理,减少了代码间的直接依赖。
- 便于测试:由于依赖可以通过配置或注解的形式指定,因此可以很容易地为测试替换真实的依赖。
- 更好地管理Bean生命周期:Spring容器负责Bean的创建、初始化、销毁等生命周期管理,开发者只需关注业务逻辑。
Spring IoC极大地简化了Java EE应用开发中的复杂性,使得开发者能够更加专注于业务逻辑的实现而非基础设施的搭建。通过合理利用Spring IoC,可以构建出更加灵活、可扩展的应用程序。
java 二分查找
public static int binarySearch(int[] arr, int target) {int left = 0;int right = arr.length - 1;while (left <= right) {int mid = left + (right - left) / 2; // 防止溢出if (arr[mid] == target) {return mid; // 找到目标值,返回索引}if (arr[mid] < target) {left = mid + 1; // 调整左边界} else {right = mid - 1; // 调整右边界}}return -1; // 未找到目标值}