Java面试题,这是一篇会一直更新的博客!欢迎大家留言~

news2024/11/25 20:15:54

Java面试题

  • 1、面向对象与面向过程
  • 2、Spring源码分析(可能比较复杂,但是看下去可能会找到让你顿悟的字眼)
    • 2.1、Spring创建Bean对象
    • 2.2 实例化(推断构造方法)

1、面向对象与面向过程

在这里插入图片描述

  • 封装:封装在于明确标识出允许外部使用的所有成员函数和数据项,内部细节对外部调用透明,外部调用无需修改或者关系内部实现
private String name;
public void setName(String name){
	this.name = "tuling_"+name;
}
//name有自己的命名规则,明显不能由外部直接赋值
  • 继承:继承基类的方法,并做出自己的改变或扩展,但是无法调用子类特有的功能
  • 多态:基于对象所属类的不同,外部对同一个方法的调用,实际执行的逻辑不同。需要三个条件:继承、方法重写、父类引用指向子类对象
public class peoper{
	public void sayName()}

public class Tom{
	public void sayName(){
		System.out.println("Tom!");
	}

public class John{
	public void sayName(){
		System.out.println("John!");
	}
}

2、Spring源码分析(可能比较复杂,但是看下去可能会找到让你顿悟的字眼)

2.1、Spring创建Bean对象

先看一段代码

@mapper
public class UserService{
	@Autowired
	private OrderService orderService;
	public void test(){
		System.out.println(orderService);
	}
}

上面这段代码中@mapper,实际上执行了Spring创建Bean对象并放入Spring容器的过程,如下

  1. UserService实例化(无参构造方法),生成普通对象
  2. 对普通对象依赖注入- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -【根据@Autowired判断是否对属性注入依赖】
  3. 初始化- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -【执行所有方法】
  4. 初始化后(AOP),生成代理对象 - - - - - - - - - - - - - - - - - - - - - - - - - - - - -【切面编程】
  5. 将普通对象或者代理对象放入,Map<beanName,Bean对象> - - - - - - - - -【即注册Bean对象】

下面对上述过程一一讲解

  1. UserService实例化,生成普通对象

这里的UserService实例化,可不是说让你自己在main()方法里面手动做一个UserService userService的实例化。而是说你在public class UserService“头顶”上加了注解@Mapper的时候,Spring“背地里”进行了第一步:将UserService实例化了,也就是UserService userService = new UserService();

  1. 使用@Autowired,对普通对象的属性进行依赖注入
public class UserService{
	/*
	在UserService对象中有一个属性OrderService,
	Spring也对该属性进行了实例化OrderService orderService
	但是实例化出来的普通对象orderService是没有值的,
	通过@Autowired的依赖注入,普通对象orderService就有了值,
	*/
	@Autowired
	private OrderService orderService;
	public void test(){
		System.out.println(orderService);
	}
}

@Autowired依赖注入的伪代码

	//1. 先创建普通对象
	UserService userService = new UserService();
	//2. 寻找在userService对象中,被@Autowired标记的属性进行依赖注入
	for (Field field:UserService.getClass().getDeclareFields()){	//依次获取属性
		if(field.isAnnotationPresent(Autowired.class)){				//判断是否需要依赖注入
			field.set(userService,??);								//依赖注入
		}
	}
  1. 初始化(执行UserService中的所有方法)
//初始化,执行UserService中的所有方法,全都成功后才能将Bean对象创建并放入Map
if (userService instanceof InitializingBean){
	((InitializingBean) userService).afterPropertiesSet();
}

为什么要执行初始化这个步骤呢?换句话说,为什么要执行所有方法呢?

//1. 通过执行方法来为创建的实例的属性admin注入值为xxx
@Override
public void afterPropertiesSet() throws Exception{
	this.admin = "xxx";
}

//2. 通过执行方法来检验创建的实例是否满足
public void afterPropertiesSet() throws Exception{
	if(sqlSession == null){
		throw new NullPointerException();
	}
}

/*
3. 个人项目经历:每个属性都要get/set方法,若是缺失了某个属性的get/set方法,
Spring启动就会报错,这也说明了初始化执行了Bean对象的所有方法
*/
  1. 初始化后(AOP),创建代理对象

AOP就是对注入依赖后的普通对象进行切面编程,从而生成代理对象。至于什么是切面编程AOP,读者就自行搜索一下吧,因为我也只是一知半解。

  1. 将普通对象或者代理对象放入,Map<beanName,Bean对象>
  • 我们先看到回到上面Spring创建Bean对象的过程,会发现有普通对象和代理对象。两者的区别,大家可以认为是普通对象经过了“加工”,变成了更多功能的代理对象。
  • 现在我们要将普通对象或者代理对象放入Map并将代理对象放入Map<beanName,Bean对象>中。
  • 如果没有进行AOP生成代理对象,那么这时候就是将普通对象放入Map中,普通对象成为Bean对象;如果进行了AOP生成代理对象,那么这时候就是将代理对象放入Map中,代理对象成为Bean对象;
  • 将普通对象或者代理对象放入Map这个动作完成了,才是真正意义上生成了Bean对象,也就是注册了Bean

2.2 实例化(推断构造方法)

首先我们给出一段代码,这个后面讲解有参构造器要用,这里先告诉读者存在这个类

@Component
public class OrderService{
}
  1. 没有写出构造器,默认存在一个无参构造器
@Service
public class UserService{
	private OrderService orderService;
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
输出:null

  1. 写一个有参构造器,那么构造器就只有这个有参构造器
@Service
public class UserService{
	private OrderService orderService;
	public UserService(OrderService orderService){
		this.orderService = orderService;
		System.out.println(1);
	}
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
输出:1、#{orderService指针编号}

  1. 写一个无参构造器和一个有参构造器,那么就存在两个构造器
@Service
public class UserService{
	private OrderService orderService;
	public UserService(){
		System.out.println(0);
	}
	public UserService(OrderService orderService){
		this.orderService = orderService;
		System.out.println(1);
	}
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
输出:0、null

  1. 编写一个有参构造器,那么就存在一个有参构造器
@Service
public class UserService{
	private OrderService orderService;
	public UserService(OrderService orderService1,OrderService orderService2){
		this.orderService = orderService;
		System.out.println(2);
	}
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
输出:2、#{orderService指针编号}

  1. 编写如下两个有参构造器
@Service
public class UserService{
	private OrderService orderService;
	public UserService(OrderService orderService){
		this.orderService = orderService;
		System.out.println(1);
	}
	public UserService(OrderService orderService1,OrderService orderService2){
		this.orderService = orderService;
		System.out.println(2);
	}
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
报错!Caused by:com.zhouyu.service.UserService.< init >()

总结

  • 如果没有重写构造方法,那么创建Bean对象就会用无参构造方法;
  • 如果重写了唯一 一个有参构造方法,那么创建Bean对象就会用该有参构造方法;
  • 如果重写了两个有参构造方法,那么创建Bean对象不知道用哪个有参构造方法,就会去寻找无参构造方法,如果没有无参构造方法就报错。如果存在无参构造方法就执行无参构造方法。
  1. 那么有没有办法使用指定的构造方法?通过@Autowired实现
@Service
public class UserService{
	private OrderService orderService;
	
	@Autowired		//指定使用该构造方法,即使存在无参构造器,也要使用这个有参构造器
	public UserService(OrderService orderService){
		this.orderService = orderService;
		System.out.println(1);
	}
	public UserService(OrderService orderService1,OrderService orderService2){
		this.orderService = orderService;
		System.out.println(2);
	}
	public void test(){
		System.out.println(orderService);
	}
}

执行UserService userService = (UserService) applicationContext.getBean(“UserService”);
输出:1、#{orderService指针编号}

  1. 有参构造器public UserService(OrderService orderService)中,参数orderService经过test打印出来不是空的,那么是谁将值传给orderService的呢?
  • 当我们创建Bean对象userService时,需要用到有参构造方法,Spring就会在Map中寻找Bean对象OrderService,并且注入到构造方法的参数orderService中。
  • 当然这个Bean对象OrderService早就在 2.2 开头的那段代码给出了,@Component就把OrderService注册成了Bean对象。
  • 如果将@Component去掉,那么OrderService就无法成为Bean对象,那么Spring也拿不出Bean对象来传给UserService的有参构造方法的参数orderService,那么orderService就为空。但是Spring规定了不能向有参构造方法的参数传null。所以这种情况运行就会出现下面结果:
报错:No qualifying bean of type 'com.zhouyu.service.OrderService'
  1. 那么Spring怎样从Map<beanName,Bean对象>中,找到合适的Bean对象传入有参构造器的参数中?因为可能同一个类注册了多个bean。
  • 如果通过参数的类OrderService找出beanName唯一,那就直接将Bean对象注入orderService。
  • 如果通过参数的类OrderService找出beanName不唯一,那就通过参数名orderService找出唯一的beanName,然后将Bean对象注入orderService参数
  • 如果这样都找不到,那就报错!
  • 如下这三个orderService,orderService1,orderService2分别是可选的beanName,将构造器public UserService(OrderService orderService)的参数orderService改成上述之一即可不报错。
expected single matching bean but found 3:orderService,orderService1,orderService2
  1. 循环依赖(了解)
@Component
public class OrderService{
	private UserService userService;
	public OrderService(UserService userService){
		this.userService = userService;
	}
}
@Service
public class UserService{
	private OrderService orderService;
	public UserService(OrderService orderService){
		this.orderService = orderService;
	}
}
报错:Is there an unresolvable circular reference?

我们来看一下过程:当我要将UserService创建为Bean对象时,那么就需要传入OrderService的Bean对象给orderService。那么OrderService要提前被Spring创建为Bean对象是不是?那我们看看OrderService要提前被Spring创建为Bean对象也是用到有参构造器,需要传入UserService的Bean对象,那么UserService要提前被Spring创建为Bean对象…这样就陷入了循环了(circular reference)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154102.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

快递驿站取件管理系统|基于SpringBoot的快递栈系统设计与实现

作者主页&#xff1a;编程指南针 作者简介&#xff1a;Java领域优质创作者、CSDN博客专家 、掘金特邀作者、多年架构师设计经验、腾讯课堂常驻讲师 主要内容&#xff1a;Java项目、毕业设计、简历模板、学习资料、面试题库、技术互助 收藏点赞不迷路 关注作者有好处 文末获取源…

商场楼层地图怎么制作,高效、便捷的商场二三维地图绘制平台

当顾客走进庞大的商场购物中心&#xff0c;如何让顾客在商场购物消费时有更轻松方便的体验&#xff1f;如何能快速将品牌和商品传递给潜在顾客&#xff0c;并一键引导顾客到店&#xff1f;电子地图作为大家最喜闻乐见的高效应用形式&#xff0c;在商业应用中&#xff0c;不论针…

arduinoIDE下载keypad和password库文件

任务需求&#xff1a;需要使用4*4矩阵键盘来完成一个按键密码锁 需要使用keypad和password这两个开源库 开源库的查找 1.在IDE中直接查找 同时在更多中能够看到api文档 2.在官网中进行找寻 至于导入的方式比较简单就不做叙述 keypad库文件文档api分析 api可以在官网中有…

用Python找出了删除自己微信的所有人并将他们自动化删除了

用Python找出了删除自己微信的所有人并将他们自动化删除了 你是否有微信被删了好友不自知&#xff0c;还傻傻的给对方发消息&#xff0c;结果出现了下图中那尴尬的一幕的经历呢&#xff1f;其实我们可以用Python提前把他们找出来并自动化删除避免尴尬的。 为了避免再次出现上…

Tools for better thinking

内容来自untools官网&#xff0c;感兴趣的可以去翻译一下&#xff0c;我只做下总结 理解系统 Concept mapConnection circlesIceberg ModelBalancing feedback loopReinforcing feedback loop 做出决策 Cynefin frameworkSix Thinking HatsSecond-order thinkingEisenhower Mat…

【LeetCode】753. 破解保险箱

753. 破解保险箱 题目描述 有一个需要密码才能打开的保险箱。密码是 n 位数, 密码的每一位是 k 位序列 0, 1, ..., k-1 中的一个 。 你可以随意输入密码&#xff0c;保险箱会自动记住最后 n 位输入&#xff0c;如果匹配&#xff0c;则能够打开保险箱。 举个例子&#xff0c…

怎么看电脑配置?Windows和Mac系统配置的查看方法

电脑的配置一般指电脑硬件配件的高档程度和性价比&#xff0c;计算机的性能主要取决于主要的硬件配置。很多朋友在购买电脑之前应该注意查看电脑的配置&#xff0c;怎么看电脑配置&#xff1f;下面有关于Windows系统和Mac系统电脑配置的不同查看方式&#xff0c;一起来看看吧&a…

光遗传学应用中所涉及到的光纤产品盘点!

如上图所示&#xff0c;在光遗传学的应用中&#xff0c;会使用到如光遗传跳线、光遗传插芯针、光纤旋转器、光纤耦合器/分束器&#xff08;12或22&#xff09;等产品。对于这些产品&#xff0c;根据不同的应用&#xff0c;又涉及到光纤芯径、数值孔径NA、出纤长度、插芯直径等众…

如何拖拽图片放到指定的格子里

本文首发于微信公众号&#xff1a; 小蚂蚁教你做游戏。欢迎关注领取更多学习做游戏的原创教程资料&#xff0c;每天学点儿游戏开发知识。嗨&#xff01;大家好&#xff0c;我是小蚂蚁。今天来分享一个如何在游戏中拖拽一个图片&#xff0c;然后把它放到指定的格子里&#xff0c…

网络编程(十)——基于UDP协议的套接字

TCP和UDP协议传输对比 TCP协议传输数据可靠&#xff0c;TCP传输数据后&#xff0c;如果收到接收方回应消息&#xff0c;则会在本机缓存中删除已发送消息&#xff1b;如果没有收到接收方回应消息&#xff0c;则会利用缓存继续发送消息。UDP协议传输数据相对来说不可靠&#xff…

学生看书用白炽灯和led灯哪个好?学生led护眼灯排行榜

我们都知道学生的晶状体是比较敏感的&#xff0c;不得不承认一个实际问题&#xff0c;LED灯已经普遍到日常生活中&#xff0c;不管是教室、企业、书房&#xff0c;使用LED灯居多&#xff0c;主要是因为它的电流稳定、光线柔和、光效效率高&#xff0c;所以LED灯的灯光没有紫外线…

Qt OpenGL(07)递归细分四面体法绘制球体

文章目录Qt OpenGL通过递归细分逼近球面思路下面就是绘制的代码&#xff1a;Widget.cpp顶点着色器片段着色器Qt OpenGL通过递归细分逼近球面 在OpenGL中绘制球面&#xff0c;不是太简单的事情。因为球面和圆都不是OpenGL所支持的图元&#xff0c;因此我们将通过一种称为递归细分…

飞宇科技在创业板IPO终止:长江证券撤回保荐,吴玉飞为实控人

2023年1月10日&#xff0c;深圳证券交易所披露的信息显示&#xff0c;江苏飞宇医药科技股份有限公司&#xff08;下称“飞宇科技”&#xff09;的保荐机构&#xff08;长江证券&#xff09;提交了撤回飞宇科技首次公开发行股票并在创业板上市申请的申请因此&#xff0c;深圳证券…

BOM(二): 元素偏移量offset 、元素可视区client 、元素滚动 scroll、动画

PC端网页特效元素偏移量offset元素可视区client元素滚动 scroll 系列动画元素偏移量offset 1.offset概述 offset 系列相关属性可以动态的得到该元素的位置&#xff08;偏移&#xff09;、大小等。 获得元素距离带有定位父元素的位置获得元素自身的大小&#xff08;宽度高度&…

Python 字典(Dictionary)操作详解

这篇文章主要介绍了Python 字典(Dictionary)的详细操作方法&#xff0c;需要的朋友可以参考下。 Python字典是另一种可变容器模型&#xff0c;且可存储任意类型对象&#xff0c;如字符串、数字、元组等其他容器模型。 一、创建字典 字典由键和对应值成对组成。字典也被称作关…

微信小程序云开发之新闻博客社区项目debug后的项目代码

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a;lqj_本人的博客_CSDN博客-微信小程序,html特效,vue2基础领域博主 本次文章主要时为我最近在哔哩哔哩上的新发布的视频做一个映射&#xff01; 哔哩哔哩欢迎关注&#xff1a;小淼前端 哔…

【Python从入门到进阶】3、运行python代码

接上篇《2、Python环境的安装》 上一篇我们学习了如何下载安装Python编程环境&#xff0c;以及如何使用pip管理Python包。本篇我们来学习如何使用终端和执行文件运行python代码。 一、终端运行 我们可以在命令行终端进入python解释程序&#xff0c;直接输入python代码&#x…

Spring Cloud OpenFeign @SpringQueryMap注解

概述 我们在使用GetMapping方法是&#xff0c;对于多个参数都是通过RequestParam参数一个一个接取的&#xff0c;多个参数时会比较麻烦&#xff0c;能像RequestBody那样接取PostMapping的参数么&#xff1f;答案是可以的。 SpringQueryMap介绍 SpringQueryMap 注解是 spring…

关于数据管理、数据治理和数据资产,你搞得清楚吗?

全球数字化的趋势愈演愈烈&#xff0c;我国信息化规模日渐增大&#xff0c;我们也每天都在接收大量的数据&#xff0c;要想深度挖掘数据的价值&#xff0c;首先从搞清楚数据的概念入手。今天我们就来聊一聊数据管理、数据治理和数据资产的概念和它们之间的相互关系。 数据管理…

从低代码来看,何谓客户体验自动化

在当今竞争激烈的大环境下&#xff0c;拥有出色的产品或服务并不意味着100%成功&#xff0c;反而是客户在购买流程中的体验变得比以往任何时候都更加重要。 随着企业业务的发展&#xff0c;提供个性化的客户体验变得愈加困难&#xff0c;许多企业因无法提供令人满意的客户体验而…