2024年java基础部分易混淆问题总结

java基础部分易混淆问题总结目录 一 try catch finally 内部代码执行顺序 二 synchronized 和 Lock 区别是什么 三 线程休眠 阻塞 的几种方法 休眠方法之间的联系与区别 四 notify 是随机唤醒还是顺序唤醒 五 maven 是怎样解决依赖冲突的 六 Spring Boot 的 starter 机制是什么 java 基础部分易混淆问题总结 七

大家好,我是讯享网,很高兴认识大家。



目录

一、try-catch-finally内部代码执行顺序

二、synchronized和Lock区别是什么?

三、线程休眠(阻塞)的几种方法

休眠方法之间的联系与区别

四、notify是随机唤醒还是顺序唤醒

五、maven是怎样解决依赖冲突的

六、Spring Boot的starter机制是什么

java基础部分易混淆问题总结

七、Springboot自动配置具体实现步骤

八、Spring的@Autowired注解为什么用在接口上

九、Spring Bean的生命周期

十、Java动态代理InvocationHandler和Proxy

1、Proxy

2、InvocationHandler

3、实例


一、try-catch-finally内部代码执行顺序

 
讯享网 

执行顺序:

        先执行try中代码,如果没异常就在try中return语句执行之后,返回之前跳转执行finally中代码。

        如果有异常,就在遇到异常之后跳转执行catch中代码,并在catch中return语句执行之后,返回之前跳转执行finally中代码。

        但需要注意的是,在执行finally中代码之前,try中return的值已经确定,例如若try中代码最后为return a+b,此时a=1,b=2。则程序会将3保存起来,不管finally中对a、b做什么改变,最终都会返回3。但若干return的数据时引用数据类型,则在finally中对该引用数据类型的属性值的改变起作用。

        finally中如果包含return,那么程序将在这里返回,而不是try或catch中的return返回,返回值就不是try或catch中保存的返回值了。

二、synchronized和Lock区别是什么?

1、类型不同:synchronized是一个关键字,而lock是一个接口,例如ReentrantLock类就是其一个实现类。

2、获取锁和释放锁方式不同:synchronized是隐式的加锁,会自动加锁和释放锁。lock是显示的加锁,在使用之前需要先创建一个 Lock 对象,然后使用lock()和unlock()方法手动加锁和释放锁。

3、用法不同:synchronized 可用来方法和代码块,而 Lock 只能用在代码块上。

4、锁类型不同:synchronized 属于非公平锁,而 ReentrantLock 既可以是公平锁也可以是非公平锁(默认非公平)。                                                                                                                                 公平锁指多个线程按照先到先得的策略获取锁。好处是所有线程都有机会获得锁,不会饿死。坏处是由于所有线程都会经历阻塞态,因此唤醒阻塞线程的开销会很大。                                               非公平锁指所有的线程拼运气,谁运气好,谁就获取到锁。好处是可以减少CPU唤醒线程的开销,整体的吞吐效率会高。坏处是可能会有线程长时间甚至永远获取不到锁,导致饿死。

5、响应中断不同:Lock 可以使用 lockInterruptibly 获取锁并响应中断指令,而 synchronized 不能响应中断,也就是如果发生了死锁,使用 synchronized 会一直等待下去,而使用 Lock 可以响应中断并释放锁,从而解决死锁的问题。

6、底层实现不同:synchronized采用的是monitor对象监视器,lock的底层原理是AQS。

参考来源:

http://t.csdn.cn/hUNow

三、线程休眠(阻塞)的几种方法

1、线程睡眠Thread.sleep

2、线程等待Object.wait

3、线程暂停LockSupport.park

休眠方法之间的联系与区别

1、sleep()和wait()以及park()都是可中断方法,但被中断后只有sleep()和wait()会收到中断异常。

2、sleep()后线程状态为TIMED_WAITING(限期等待),wait()以及park()后线程状态为WAITING(无限期等待)。

3、sleep()以及park()不会释放持有的锁,而wait()会释放持有的锁。

4、三个方法所属类不同。

5、wait()必须在同步方法中进行,sleep()不需要。

参考来源:http://t.csdn.cn/6A9k1

四、notify是随机唤醒还是顺序唤醒

notify 唤醒线程的规则是随机唤醒还是顺序唤醒取决于 JVM 的具体实现,作为主流的 HotSpot 虚拟机中的 notify 的唤醒规则是顺序的,也就是 notify 会按照线程的休眠顺序,依次唤醒线程。

五、maven是怎样解决依赖冲突的

1、路径最近者优先

相同jar不同版本,根据依赖的路径长短来决定引入哪个依赖。

     该例中X(1.0)的路径长度为3,而X(2.0)的路径长度为2,因此X(2.0)会被解析使用。 

2、第一声明原则

在pom.xml配置文件中,如果有两个名称相同,版本的不同依赖声明,先写的会生效,所以先声明自己要用的版本。这里的名称相同,版本不同的依赖声明,既可以是直接依赖,也可以是传递依赖。

六、Spring Boot的starter机制是什么

和自动配置一样,Spring Boot Starter的目的也是简化配置,而Spring Boot Starter解决的是依赖管理配置复杂的问题,有了它,当我需要构建一个Web应用程序时,不必再遍历所有的依赖包,一个一个地添加到项目的依赖管理中,而是只需要一个配置, 同理,如果想引入持久化功能,可以配置所有官方的starter都以spring-boot-starter-*的规则命名。

参考来源:https://zhuanlan.zhihu.com/p/

七、Springboot自动配置具体实现步骤

1.SpringBoot启动的时候加载主启动类,通过@EnableAutoConfiguration开启自动配置功能。

2.@EnableAutoConfiguration利用AutoConfigurationImportSelector给容器中导入一些组件。

3.通过protected List getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes)获取候选的配置和核心方法,扫描所有jar包类路径下"META-INF/spring.factories",通过@AutoConfigurationPackage自动配置包。

4.把扫描到的文件包装成Properties对象。

5.从properties中获取到EnableAutoConfiguration.class类名对应的值,并把他们添加在容器中。

6.整个过程就是将类路径下"META-INF/spring.factories"里面配置的所有EnableAutoConfiguration的值加入到容器中。

7.根据@Conditional注解中的条件判断,决定这个配置是否生效。

8.初始化Bean,自动配置完成。

总结
   SpringBoot通过@EnableAutoConfiguration开启自动装配,通过 SpringFactoriesLoader 最终加载META-INF/spring.factories中的自动配置类实现自动装配,自动配置类其实就是通过@Conditional按需加载的配置类。



参考来源:https://blog.csdn.net/yanghang1122/article/details/

八、Spring的@Autowired注解为什么用在接口上

例如在Controller中使用@Autowired时,为什么是用在Service上而不是ServiceImpl上。

        这里就要说到@Autowired的注入原理:@Autowired是Spring的注解,Autowired默认先按byType,如果发现找到多个bean,则再按照byName方式比对,如果还有多个bean,则报错Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException;                              再来说Controller获取实例的过程:使用@Autowired,程序在spring的容器中查找类型时TestService的bean,刚好找到有且只有一个此类型的bean,即TestServiceImpl,所以就把testServiceImpl自动装配到了Controller的实例TestService中。

        如果一个接口有多个实现类时,@Autowired需要结合@Qualifier("类名")使用,注:实现类的开头小写类名TestServiceImpl2->testServiceImpl2。                      

讯享网

问:为什么非要调用接口来多此一举,而不直接调用实现类serviceImpl的bean来得简单明了呢?

答:直接使用serviceImpl的bean是可以的,这样加一层接口的原因:1.AOP程序的思想,给别人调用的接口,调用这只想知道方法和功能,而对于这个方法内部逻辑实现并不关心。2.降低各个模块间的关联,实现松耦合、程序分成、最主要的体现了继承只能单继承,接口却可以多实现

参考来源:https://blog.csdn.net/m0_/article/details/

九、Spring Bean的生命周期

 内容较多,结合着看:Springbean生命周期详解_爱吃巧克力的小男孩的博客-CSDN博客_springbean生命周期详解

十、Java动态代理InvocationHandler和Proxy

        提到动态代理,就不得不提到其两个重要的类和接口InvocationHandler(接口)Proxy(类),这一个类Proxy和接口InvocationHandler是我们实现动态代理的核心。

1、Proxy

首先简单梳理一下,假设存在一个被代理类Teacher,我们要生成其的代理类proxy,我们需要调用 Proxy 的 newProxyInstance 方法来生成代理类,而newProxyInstance方法有三个参数:              参数1 类加载器
        ClassLoader classLoader = person.getClass().getClassLoader();
参数2 被代理对象实现的所有的接口的字节码数组
        Class[] interfaces =person.getClass().getInterfaces();// {Court.class , ... , ...};
        Class[] interfaces={Court.class};
参数3 执行处理器 用于定义方法的增强规则(加强后的方法)
        InvocationHandler handler =new InvocationHandler(){}                                                            这个参数3就是要将代理对象关联到InvocationHandler实现类对象上。

2、InvocationHandler

InvocationHandler接口是proxy代理实例的调用处理程序实现的一个接口,每一个proxy代理实例都有一个关联的调用处理程序;当我们通过动态代理对象调用一个方法时候,这个方法的调用就会被转发到实现InvocationHandler接口类的invoke方法来调用,看如下invoke方法:

 

我们可以在这个invoke方法中对被代理对象的方法进行增强。 

3、实例

- 首先我们定义一个接口People

讯享网

 - 再定义一个Teacher类,实现People接口,这个类是真实的对象,也是我们的被代理类

 

 - 现在我们要定义一个代理类的调用处理程序,每个代理类的调用处理程序都必须实现InvocationHandler接口,调用处理程序如下:

 

- 最后看一下主类

 

- 输出结果

 

 参考来源:http://t.csdn.cn/i2HGd

小讯
上一篇 2024-12-25 09:09
下一篇 2024-12-30 13:44

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/8020.html