每日一题 - 202401
1-31
什么是同步?
同步 IO 和 非同步 IO 是操作系统级别的,主要描述操作系统在收到程序请求 IO 操作后, 如果 IO 资源没有准备好,该如何响应程序的问题。前者不响应,直到 IO 资源准备好,后者返回标记, 当 IO 资源准备好之后,再通过事件机制返回给程序。
1-30
什么是阻塞?
阻塞 IO 和 非阻塞 IO 是程序级别的,主要描述程序请求操作系统 IO 操作后, 如果 IO 资源没有准备好,那么程序该如何处理的问题,前者等待,后者继续执行(一直轮询)。
1-29
如何理解 IO 流?
从数据传输方式来讲,IO 流分为字节流和字符流,字节流处理二进制文件,字符流读取单个字符,用于处理文本文件。
从数据流向来讲,IO 流分为输入流和输出流,输入流用于读取数据,输出流用于写入数据。
从数据操作类型来讲,IO 流分为文件流、管道流、缓冲流、数据流、对象流、序列化流、打印流、转换流等。
1-28
描述异常的底层?
JAVA 代码编译之后,会生成一个异常表(Exception Table),如下:
public static void simpleTryCatch() {
try {
testNPE();
} catch (Exception e) {
e.printStackTrace();
}
}
该段代码编译后生成的字节码如下:
//javap -c Main
public static void simpleTryCatch();
Code:
0: invokestatic #3 // Method testNPE:()V
3: goto 11
6: astore_0
7: aload_0
8: invokevirtual #5 // Method java/lang/Exception.printStackTrace:()V
11: return
Exception table:
from to target type
0 3 6 Class java/lang/Exception
异常表包含了可能发生异常的起始点、结束点、异常处理代码的起始点、异常类型等信息。当发生异常时,JVM 会根据异常表中的信息来决定如何处理异常。
1-27
Java 7 的 try-with-resource?
Java 7 引入了 try-with-resource 语句,该语句可以自动关闭实现了 AutoCloseable 接口的资源。 大部分的 JAVA 标准资源都继承了该接口。当在 try 代码块执行后货异常处理后,会自动调用资源的 close() 方法。
public class TryWithResourceTest {
@Test
public void test() throws IOException {
try (FileInputStream fis = new FileInputStream("test.txt")) {
int data = fis.read();
while (data != -1) {
System.out.print((char) data);
data = fis.read();
}
}
}
}
1-26
JAVA throw 和 throws 的区别?
- throw 用在方法体内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并终止当前方法的执行。
- throws 用在方法声明后面,跟的是异常类名,可以跟多个异常类名,用逗号隔开,表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(将异常抛给调用者), 如果调用者也不处理异常,那么继续往上抛,最终抛给 JVM 处理,JVM 会终止程序的运行。
1-25
getName、getCanonicalName 与 getSimpleName 的区别?
- getName():获取全限定类名,包含包名。
- getCanonicalName():获取全限定类名,不包含包名。
- getSimpleName():获取类名,不包含包名。
1-24
什么是反射?
反射是指程序可以访问、检测和修改它本身状态或行为的一种能力。 Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方法和属性。
如下:
@Test
public void classTest() throws Exception {
// 获取Class对象的三种方式
logger.info("根据类名: \t" + User.class);
logger.info("根据对象: \t" + new User().getClass());
logger.info("根据全限定类名:\t" + Class.forName("com.test.User"));
// 常用的方法
logger.info("获取全限定类名:\t" + userClass.getName());
logger.info("获取类名:\t" + userClass.getSimpleName());
logger.info("实例化:\t" + userClass.newInstance());
}
1-23
Quartz是做什么用的?
Quartz 是开源的 JAVA 任务调度框架,能够灵活且简单的管理定时任务。支持数据库集成、集群、插件等。支持使用 cron-like
表达式。
1-22
如何限制规定泛型的范围?
可以使用 extends
关键字: class Test<T extends Number>
限制泛型的范围为 Number 及其子类。
也可以使用 interface
关键字: class Test<T implements Test>
限制泛型的范围为 Test 的实现方法。
1-21
泛型类如何定义使用?
class Test<T>{ // 此处可以随便写标识符号,T是type的简称
private T t; // 类型由T指定,即:由外部指定
public void setT(T t){
this.t = t;
}
public T getT(){
return t;
}
}
public class TestDemo{
public static void main(String[] args){
Test<String> test = new Test<String>();
test.setT("hello");
System.out.println(test.getT());
}
}
1-20
this() & super() 在构造方法中的区别?
- 调用super()必须写在子类构造方法的第一行, 否则编译不通过
- super从子类调用父类构造, this在同一类中调用其他构造均需要放在第一行
- 尽管可以用this调用一个构造器, 却不能调用2个
- this和super不能出现在同一个构造器中, 否则编译不通过
- this()、super()都指的对象,不可以在static环境中使用
- 本质this指向本对象的指针。super是一个关键字
1-19
什么是 Java 移位运算符?
<<
左移运算符,num << 1,相当于 num 乘以 2>>
右移运算符,num >> 1,相当于 num 除以 2>>>
无符号右移运算符,忽略符号位,空位都以0补齐
1-18
JAVA 能在 Switch 中使用 String 吗?
在 Java 7 之前,switch 只能支持 byte、short、char、int、enum 类型,Java 7 之后,可以支持 String 类型。
1-17
为什么DNS通常基于 UDP?
DNS 通常基于 UDP,因为 UDP 没有连接的开销,而且 DNS 服务需要尽可能快地响应请求,而不是等待连接建立。但当数据长度大于512字节时,为保证传输质量,就会使用基于TCP的实现形式。
1-16
TCP 三次握手中,最后一次回复丢失,会发生什么?
如果最后一次回复丢失,客户端会认为服务端没有收到确认信息,会再次发送确认信息,服务端收到确认信息后,会再次发送确认信息,客户端收到确认信息后,会再次发送确认信息,如此循环,直到连接超时。
1-15
什么是 TCP 三次握手?
TCP 三次握手是指建立 TCP 连接时,客户端和服务端需要进行三次通信,以确认双方的接收能力和发送能力是否正常。
- 发送端首先发送一个带SYN(synchronize)标志的数据包给接收方【第一次的seq序列号是随机产生的,这样是为了网络安全,如果不是随机产生初始序列号,黑客将会以很容易的方式获取到你与其他主机之间的初始化序列号,并且伪造序列号进行攻击】
- 接收端收到后,回传一个带有SYN/ACK(acknowledgement)标志的数据包以示传达确认信息【SYN 是为了告诉发送端,发送方到接收方的通道没问题;ACK 用来验证接收方到发送方的通道没问题】
- 最后,发送端再回传一个带ACK标志的数据包,代表握手结束若在握手某个过程中某个阶段莫名中断,TCP协议会再次以相同的顺序发送相同的数据包
1-14
什么是754层网络模型?
OSI依层次结构来划分:应用层(Application)、表示层(Presentation)、会话层(Session)、传输层(Transport)、网络层(Network)、数据链路层(Data Link)、物理层(Physical)
1-13
什么是日志系统和日志门面?
日志系统是用来记录应用程序运行时的状态信息,比如错误日志、警告日志、调试日志等。
- Log4j
- Logback
- Log4j2
日志门面是一种日志系统的抽象,它定义了一组日志系统的公共接口,以便于应用程序通过这组公共接口来记录日志,而不用关心具体的日志系统实现。
- SLF4J
- Commons Logging
- Log4j-to-SLF4J
1-12
什么是 JWT?
JWT(JSON Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于作为 JSON 对象在各方之间安全地传输信息。
通过非对称加密算法,可以对 JWT 进行签名,从而保证 JWT 的真实性和完整性。
1-11
Spring Security 的原理?
SpringSecurity 的核心是一个过滤器链,它由一系列的过滤器组成,每个过滤器负责一项安全控制功能,比如认证、授权、会话管理等。
1-10
什么是 Spring Security?
SpringSecurity 是基于 Spring 的安全框架,它提供了较为全面的一套安全性解决方案,并且可以与 SpringMVC、SpringBoot 等框架无缝集成。 它充分利用了依赖注入和 AOP 技术,可以将安全性应用到方法调用或 Web 请求上,为应用系统提供声明式的安全访问控制功能。
1-9
谈谈你对 CGLib 的理解?
JDK 动态代理机制只能代理实现接口的类,一般没有实现接口的类不能进行代理。使用 CGLib 实现动态代理,完全不受代理类必须实现接口的限制。
CGLib 的原理是对指定目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理。
CGLib 的调用流程就是通过调用拦截器的 intercept 方法来实现对被代理类的调用。而拦截逻辑可以写在 intercept 方法的 invokeSuper(o, objects);的前后实现拦截。
1-8
有哪些AOP Advice通知的类型?
- 前置通知(Before advice) : 这些类型的 Advice 在 joinpoint 方法之前执行,并使用 @Before 注解标记进行配置。
- 后置通知(After advice) : 这些类型的 Advice 在连接点方法之后执行,无论方法退出是正常还是异常返回,并使用 @After 注解标记进行配置。
- 返回后通知(After return advice) : 这些类型的 Advice 在连接点方法正常执行后执行,并使用@AfterReturning 注解标记进行配置。
- 环绕通知(Around advice) : 些类型的 Advice 在连接点之前和之后执行,并使用 @Around 注解标记进行配置。
- 抛出异常后通知(After throwing advice) : 仅在 joinpoint 方法通过抛出异常退出并使用 @AfterThrowing 注解标记配置时执行。
1-7
AOP 包含的几个概念?
- 切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。
- 连接点(Joinpoint): 程序执行过程中的某个特定的点,比如某方法调用的时候或者处理异常的时候。
- 通知(Advice): 在切面的某个特定的连接点上执行的动作。
- 切入点(Pointcut): 匹配连接点的断言,在 AOP 中通知和一个切入点表达式关联。
- 引入(Introduction): 在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
- 目标对象(Target Object): 被一个或者多个切面所通知的对象,也称为被通知(advised)对象。
- 织入(Weaving): 把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象,这些可以在运行期完成,也可以在编译期完成。
1-6
列举一些重要的Spring模块。
- Spring Core:核心容器,提供 IoC 和 DI 的功能。
- Spring AOP:面向切面编程,提供声明式事务管理。
- Spring Aspects:提供与 AspectJ 的集成功能。
- Spring JDBC:提供了 JAVA 数据库连接功能。
- Spring Web:提供了基本的 Web 开发功能。
- Spring MVC:提供了 MVC 模式的 Web 开发功能。
- Spring ORM:提供了对常见的 ORM 框架的支持,如 Hibernate、JPA 等。
- Spring Test:提供了对 JUnit 和 TestNG 的支持。
- Spring Session:提供了对 Session 的集成支持。
- Spring Security:提供了对安全认证和授权的支持。
1-5
什么是监听器?
监听器是 Servlet 规范中的一种组件,可以监听 ServletContext、HttpSession、ServletRequest 等域对象的创建和销毁,以及域对象中属性的变化。
配置示例:
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
// ServletContext 创建时执行
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// ServletContext 销毁时执行
}
}
使用示例:
@Configuration
public class MyConfig {
@Bean
public ServletListenerRegistrationBean<MyListener> myListener() {
return new ServletListenerRegistrationBean<>(new MyListener());
}
}
1-4
什么是拦截器?
拦截器是 SpringMVC 的一种组件,可以在请求到达控制器之前或之后执行一些操作,比如记录日志、权限校验等。
配置示例:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 在请求到达控制器之前执行
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
// 在请求到达控制器之后,视图渲染之前执行
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// 在视图渲染之后执行
}
}
使用示例:
@Configuration
public class MyConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/hello");
}
}
1-3
Spring Boot 的默认编码是?
SpringBoot 的默认编码是 UTF-8
。可以通过 spring.http.encoding.charset
属性来修改编码。
1-2
Spring Boot 应用如何优雅关闭?
SpringBoot 应用可以通过 SpringApplication.exit()
方法来优雅关闭,该方法可以用在任何地方。
1-1
Spring Boot 怎么注册事件监听器?
SpringBoot 可以通过 @EventListener
注解来注册事件监听器,该注解可以用在方法上,也可以用在类上。