JasonsGong.github.io/posts/29985.html

707 lines
106 KiB
HTML
Raw Normal View History

2024-04-02 11:00:46 +08:00
<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0,viewport-fit=cover"><title>面试题集锦 | The Blog</title><meta name="author" content="Jason"><meta name="copyright" content="Jason"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="参考资料: Java工程师面试 宝典学习说明_互联网校招面试真题面经汇总_牛客网 (nowcoder.com) Java | JavaGuide(Java面试 + 学习指南) 一.Java基础面试题1.谈谈你对面向对象的理解​ 对比面向过程,是两种不同处理问题的角度,面向过程更注重事情的每一步骤及顺序,面向对象更注重事情有哪些参与者(对象),以及各自需要做什么。面向过程比较直接高效,面向对象易于">
2023-09-22 21:57:28 +08:00
<meta property="og:type" content="article">
<meta property="og:title" content="面试题集锦">
2024-05-10 10:21:35 +08:00
<meta property="og:url" content="https://qingling.icu/posts/29985.html">
2023-09-22 21:57:28 +08:00
<meta property="og:site_name" content="The Blog">
2024-04-02 11:00:46 +08:00
<meta property="og:description" content="参考资料: Java工程师面试 宝典学习说明_互联网校招面试真题面经汇总_牛客网 (nowcoder.com) Java | JavaGuide(Java面试 + 学习指南) 一.Java基础面试题1.谈谈你对面向对象的理解​ 对比面向过程,是两种不同处理问题的角度,面向过程更注重事情的每一步骤及顺序,面向对象更注重事情有哪些参与者(对象),以及各自需要做什么。面向过程比较直接高效,面向对象易于">
2023-09-22 21:57:28 +08:00
<meta property="og:locale" content="zh_CN">
2024-06-14 22:00:25 +08:00
<meta property="og:image" content="https://qingling.icu/img/4.png">
2023-09-22 21:57:28 +08:00
<meta property="article:published_time" content="2023-09-03T12:43:48.000Z">
2024-04-02 11:00:46 +08:00
<meta property="article:modified_time" content="2024-04-02T01:20:43.166Z">
2023-09-22 21:57:28 +08:00
<meta property="article:author" content="Jason">
<meta property="article:tag" content="面试">
<meta name="twitter:card" content="summary">
2024-06-14 22:00:25 +08:00
<meta name="twitter:image" content="https://qingling.icu/img/4.png"><link rel="shortcut icon" href="/img/%E5%9B%BE%E6%A0%87.png"><link rel="canonical" href="https://qingling.icu/posts/29985.html"><link rel="preconnect" href="//fastly.jsdelivr.net"/><link rel="preconnect" href="//busuanzi.ibruce.info"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="/cdn/icon/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="/cdn/css/snackbar.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="/cdn/css/fancybox.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = {
2023-09-22 21:57:28 +08:00
root: '/',
algolia: undefined,
localSearch: {"path":"/search.xml","preload":true,"top_n_per_article":1,"unescape":false,"languages":{"hits_empty":"找不到您查询的内容:${query}","hits_stats":"共找到 ${hits} 篇文章"}},
translate: undefined,
noticeOutdate: undefined,
highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":400},
copy: {
success: '复制成功',
error: '复制错误',
noSupport: '浏览器不支持'
},
relativeDate: {
homepage: true,
post: true
},
runtime: '天',
dateSuffix: {
just: '刚刚',
min: '分钟前',
hour: '小时前',
day: '天前',
month: '个月前'
},
copyright: undefined,
lightbox: 'mediumZoom',
2023-12-09 14:21:01 +08:00
Snackbar: {"chs_to_cht":"你已切换为繁体","cht_to_chs":"你已切换为简体","day_to_night":"你已切换为深色模式","night_to_day":"你已切换为浅色模式","bgLight":"#006650","bgDark":"#006650","position":"top-center"},
2023-09-22 21:57:28 +08:00
source: {
justifiedGallery: {
2023-09-30 18:36:25 +08:00
js: 'https://fastly.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.js',
css: 'https://fastly.jsdelivr.net/npm/flickr-justified-gallery/dist/fjGallery.min.css'
2023-09-22 21:57:28 +08:00
}
},
isPhotoFigcaption: false,
islazyload: false,
2023-12-10 21:57:00 +08:00
isAnchor: true,
2023-09-22 21:57:28 +08:00
percent: {
toc: true,
rightside: false,
},
2023-12-09 19:59:36 +08:00
autoDarkmode: true
2023-09-22 21:57:28 +08:00
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = {
title: '面试题集锦',
isPost: true,
isHome: false,
isHighlightShrink: false,
isToc: true,
2024-04-02 11:00:46 +08:00
postUpdate: '2024-04-02 09:20:43'
2023-09-22 21:57:28 +08:00
}</script><noscript><style type="text/css">
#nav {
opacity: 1
}
.justified-gallery img {
opacity: 1
}
#recent-posts time,
#post-meta time {
display: inline !important
}
</style></noscript><script>(win=>{
win.saveToLocal = {
set: function setWithExpiry(key, value, ttl) {
if (ttl === 0) return
const now = new Date()
const expiryDay = ttl * 86400000
const item = {
value: value,
expiry: now.getTime() + expiryDay,
}
localStorage.setItem(key, JSON.stringify(item))
},
get: function getWithExpiry(key) {
const itemStr = localStorage.getItem(key)
if (!itemStr) {
return undefined
}
const item = JSON.parse(itemStr)
const now = new Date()
if (now.getTime() > item.expiry) {
localStorage.removeItem(key)
return undefined
}
return item.value
}
}
win.getScript = url => new Promise((resolve, reject) => {
const script = document.createElement('script')
script.src = url
script.async = true
script.onerror = reject
script.onload = script.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
script.onload = script.onreadystatechange = null
resolve()
}
document.head.appendChild(script)
})
win.getCSS = (url,id = false) => new Promise((resolve, reject) => {
const link = document.createElement('link')
link.rel = 'stylesheet'
link.href = url
if (id) link.id = id
link.onerror = reject
link.onload = link.onreadystatechange = function() {
const loadState = this.readyState
if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
link.onload = link.onreadystatechange = null
resolve()
}
document.head.appendChild(link)
})
win.activateDarkMode = function () {
document.documentElement.setAttribute('data-theme', 'dark')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
}
}
win.activateLightMode = function () {
document.documentElement.setAttribute('data-theme', 'light')
if (document.querySelector('meta[name="theme-color"]') !== null) {
document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
}
}
const t = saveToLocal.get('theme')
2023-12-09 19:59:36 +08:00
const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches
const isLightMode = window.matchMedia('(prefers-color-scheme: light)').matches
const isNotSpecified = window.matchMedia('(prefers-color-scheme: no-preference)').matches
const hasNoSupport = !isDarkMode && !isLightMode && !isNotSpecified
if (t === undefined) {
if (isLightMode) activateLightMode()
else if (isDarkMode) activateDarkMode()
else if (isNotSpecified || hasNoSupport) {
const now = new Date()
const hour = now.getHours()
const isNight = hour <= 8 || hour >= 22
isNight ? activateDarkMode() : activateLightMode()
}
window.matchMedia('(prefers-color-scheme: dark)').addListener(function (e) {
if (saveToLocal.get('theme') === undefined) {
e.matches ? activateDarkMode() : activateLightMode()
}
})
} else if (t === 'light') activateLightMode()
else activateDarkMode()
2023-09-22 21:57:28 +08:00
const asideStatus = saveToLocal.get('aside-status')
if (asideStatus !== undefined) {
if (asideStatus === 'hide') {
document.documentElement.classList.add('hide-aside')
} else {
document.documentElement.classList.remove('hide-aside')
}
}
const detectApple = () => {
if(/iPad|iPhone|iPod|Macintosh/.test(navigator.userAgent)){
document.documentElement.classList.add('apple')
}
}
detectApple()
2024-06-14 22:00:25 +08:00
})(window)</script><script src="https://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script><script type="text/javascript" src ="/js/welcome.js" ></script><script src="/js/sweetalert.js"></script><link rel="stylesheet" href="/css/sweetalert.css"><!-- hexo injector head_end start --><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.css" media="print" onload="this.media='all'"><link rel="stylesheet" href="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiperstyle.css" media="print" onload="this.media='all'"><!-- hexo injector head_end end --><meta name="generator" content="Hexo 6.3.0"></head><body><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="avatar-img is-center"><img src="/img/avatar.jpg" onerror="onerror=null;src='/img/loading.gif'" alt="avatar"/></div><div class="sidebar-site-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">60</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">39</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">10</div></a></div><br/><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw fas fa-stream"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/"><i class="fa-fw fas fa-list"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div></div></div><div class="post" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog-info"><a href="/" title="The Blog"><img class="site-icon" src="/img/logo.png"/><span class="site-name">The Blog</span></a></span><div id="menus"><div id="search-button"><a class="site-page social-icon search" href="javascript:void(0);"><i class="fas fa-search fa-fw"></i><span> 搜索</span></a></div><div class="menus_items"><div class="menus_item"><a class="site-page" target="_blank" rel="noopener" href="https://www.tutorialspoint.com/compile_java8_online.php"><i class="fa-fw fas fa-code"></i><span> 代码</span></a></div><div class="menus_item"><a class="site-page" href="/notice/"><i class="fa-fw fas fa-stream"></i><span> 公告</span></a></div><div class="menus_item"><a class="site-page" href="/website/"><i class="fa-fw fas fa-list"></i><span> 网址</span></a></div><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 主页</span></a></div></div><div id="toggle-menu"><a class="site-page" href="javascript:void(0);"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div id="post"><div id="post-info"><h1 class="post-title">面试题集锦</h1><div id="post-meta"><div class="meta-firstline"><span class="post-meta-date"><i class="far fa-calendar-alt fa-fw post-meta-icon"></i><span class="post-meta-label">发表于</span><time class="post-meta-date-created" datetime="2023-09-03T12:43:48.000Z" title="发表于 2023-09-03 20:43:48">2023-09-03</time><span class="post-meta-separator">|</span><i class="fas fa-history fa-fw post-meta-icon"></i><span class="post-meta-label">更新于</span><time class="post-meta-date-updated" datetime="2024-04-02T01:20:43.166Z" title="更新于 2024-04-02 09:20:43">2024-04-02</time></span><span class="post-meta-categories"><span class="post-meta-separator">|</span><i class="fas fa-inbox fa-fw post-meta-icon"></i><a class="post-meta-categories" href="/categories/%E9%9D%A2%E8%AF%95/">面试</a></span></div><div class="meta-secondline"><span class="post-meta-separator">|</span><span class="post-meta-wordcount"><i class="far fa-file-word fa-fw post-meta-icon"></i><span class="post-meta-label">字数总计:</span><span class="word-count">13
2024-04-02 11:00:46 +08:00
<p><a target="_blank" rel="noopener" href="https://www.nowcoder.com/issue/tutorial?tutorialId=94&uuid=ea1986fcff294f6292385703e94689e8">Java工程师面试 宝典学习说明_互联网校招面试真题面经汇总_牛客网 (nowcoder.com)</a></p>
2023-09-26 18:57:45 +08:00
<p><a target="_blank" rel="noopener" href="https://javaguide.cn/java/">Java | JavaGuide(Java面试 + 学习指南)</a></p>
2023-09-22 21:57:28 +08:00
<h2 id="一-Java基础面试题"><a href="#一-Java基础面试题" class="headerlink" title="一.Java基础面试题"></a>一.Java基础面试题</h2><h3 id="1-谈谈你对面向对象的理解"><a href="#1-谈谈你对面向对象的理解" class="headerlink" title="1.谈谈你对面向对象的理解"></a>1.谈谈你对面向对象的理解</h3><p> 对比面向过程,是两种不同处理问题的角度,面向过程更注重事情的每一步骤及顺序,面向对象更注重事情有哪些参与者(对象),以及各自需要做什么。面向过程比较直接高效,面向对象易于复用、扩展和维护。</p>
<p>面向对象的三大基本特征:封装、继承、多态(父类应用指向子类对象)</p>
<h3 id="2-JDK、JRE、JVM之间的区别"><a href="#2-JDK、JRE、JVM之间的区别" class="headerlink" title="2.JDK、JRE、JVM之间的区别"></a>2.JDK、JRE、JVM之间的区别</h3><p>JDK java 开发工具</p>
<p>JRE(Java Runtime Environment Java 运行环境)</p>
<p>JVM java虚拟机</p>
<p>JDK &#x3D; JRE + 开发工具集(例如 Javac,java 编译工具等)</p>
<p>JRE &#x3D; JVM + Java SE 标准类库java 核心类库)</p>
<h3 id="3-和equals⽅法的区别"><a href="#3-和equals⽅法的区别" class="headerlink" title="3.&#x3D;&#x3D;和equals⽅法的区别"></a>3.&#x3D;&#x3D;和equals⽅法的区别</h3><p>&#x3D;&#x3D;:如果是基本数据类型,⽐较是值,如果是引⽤类型,⽐较的是引⽤地址<br>equals具体看各个类重写equals⽅法之后的⽐较逻辑⽐如String类虽然是引⽤类型但是String类中重写了equals⽅法⽅法内部⽐较的是字符串中的各个字符是否全部相等。</p>
<h3 id="4-String-StringBuffer-StringBuilder的区别"><a href="#4-String-StringBuffer-StringBuilder的区别" class="headerlink" title="4.String,StringBuffer,StringBuilder的区别"></a>4.String,StringBuffer,StringBuilder的区别</h3><p>1.String是不可变的如果尝试去修改会新⽣成⼀个字符串对象StringBuffer和StringBuilder是可变的,修改是在原对象上操作的</p>
<p>2.StringBuffer是线程安全的StringBuilder是线程不安全的所以在单线程环境下StringBuilder效率会更⾼</p>
<p>性能: StringBuilder &gt; StringBuffer &gt; String</p>
<h3 id="5-重载和重写的区别"><a href="#5-重载和重写的区别" class="headerlink" title="5.重载和重写的区别"></a>5.重载和重写的区别</h3><p>重载:发生在同一个类中,方法名必须相同,参数类型不同、个数不同、顺序不同、方法返回值和访问修饰符可以不同,发生在编译时。</p>
<p>重写:发生在父子类中,方法名,参数列表必须相同,返回值范围小于等于父类,抛出异常范围小于等于父类,访问修饰符范围大于等于父类;如果父类访问修饰符为私有,子类不能重写该方法。</p>
<h3 id="6-接口和抽象类的区别"><a href="#6-接口和抽象类的区别" class="headerlink" title="6.接口和抽象类的区别"></a>6.接口和抽象类的区别</h3><p>1.抽象类可以有实现的方法和抽象的方法</p>
<p>2.抽象类的成员变量可以是各种类型的接口中的成员变量只能是public static final类型(默认)的</p>
<p>3.抽象类只能继承一个,接口可以实现多个</p>
<p>4.关键字不同接口的关键字是interface,抽象类的关键字是abstract</p>
<h3 id="7-List和set的区别"><a href="#7-List和set的区别" class="headerlink" title="7.List和set的区别"></a>7.List和set的区别</h3><p>List:有序按对象进入的顺序保存对象可重复允许多个Null元素对象可以使用iterator取出所有的元素在逐一遍历还可以使用get(int index)获取指定下标的元素。</p>
<p>Set:无序不可重复最多允许有一个Null元素对象取元素时只能用iterator接口取得所有元素再逐一遍历各个元素。</p>
<h3 id="8-hashCode-与equals-之间的关系"><a href="#8-hashCode-与equals-之间的关系" class="headerlink" title="8.hashCode()与equals()之间的关系"></a>8.hashCode()与equals()之间的关系</h3><p>hashCode()的作用是获取哈希码,也称散列码,哈希码的作用是确定该对象在哈希表中的索引位置。</p>
<ul>
<li><p>如果两个对象相等那么它们的hashCode()值一定相同</p>
</li>
<li><p>如果两个对象hashCode()相等,它们并不一定相等</p>
</li>
</ul>
<h3 id="9-ArrayList和LinkedList的区别"><a href="#9-ArrayList和LinkedList的区别" class="headerlink" title="9.ArrayList和LinkedList的区别"></a>9.ArrayList和LinkedList的区别</h3><p>ArrayList基于动态数组连续内存存储适合下标访问随机访问。扩容机制因为数组长度固定超出长度存数据时需要新建数组将老数组的数据拷贝到新数组然后插入需要加入到数组中的数据。</p>
<p>LinkedList基于链表可以存储在分散的内存中适合做数据插入及删除操作不适合查询。遍历LinkedList必须使用iterator不能使用for循环因为for循环体内通过get(i)取得某一元素时都需要对list重新遍历性能消耗大。</p>
<h3 id="10-HashMap和HashTable的区别底层实现是什么"><a href="#10-HashMap和HashTable的区别底层实现是什么" class="headerlink" title="10.HashMap和HashTable的区别底层实现是什么?"></a>10.HashMap和HashTable的区别底层实现是什么?</h3><p>区别:</p>
<p>1.HashMap方法没有synchronized修饰线程非安全HashTable线程安全</p>
<p>2.HashMap允许key和value为null而HashTable不允许</p>
<p>底层实现: 数组 + 链表</p>
<h3 id="11-ConcurrentHashMap"><a href="#11-ConcurrentHashMap" class="headerlink" title="11.ConcurrentHashMap"></a>11.ConcurrentHashMap</h3><p>ConcurrentHashMap和HashTable都是线程安全的但ConcurrentHashMap相比HashTable性能更高</p>
<h3 id="12-如何实现一个IOC容器"><a href="#12-如何实现一个IOC容器" class="headerlink" title="12.如何实现一个IOC容器"></a>12.如何实现一个IOC容器</h3><p>1.配置文件配置包扫描路径</p>
<p>2.递归包扫描获取.class文件</p>
<p>3.反射、确定需要交给IOC管理的类</p>
<p>4.对需要注入的类进行依赖注入</p>
<h3 id="13-什么是字节码?采用字节码的好处是什么?"><a href="#13-什么是字节码?采用字节码的好处是什么?" class="headerlink" title="13.什么是字节码?采用字节码的好处是什么?"></a>13.什么是字节码?采用字节码的好处是什么?</h3><p><strong>什么是字节码?</strong></p>
<p>Java中引入了虚拟机的概念即在机器和编译程序之间加入了一层抽象的虚拟的机器。编译程序只需要面向虚拟机生成虚拟机能够理解的代码然后由解释器来将虚拟机代码转化为特定系统的机器码执行在java中这种供虚拟机理解的代码叫做字节码(即扩展名为.class的文件)。</p>
<p><strong>采用字节码的好处是什么?</strong></p>
<p>Java语言通过字节码的方式在一定程度上解决了传统解释型语言执行效率的问题同时又保留了解释型语言可移植的特点。所以Java程序运行时比较高效而且由于字节码并不专对一种特定的机器因此Java程序无需重新编译便可在多种计算机上运行。</p>
<h3 id="14-Java类加载器有哪些"><a href="#14-Java类加载器有哪些" class="headerlink" title="14.Java类加载器有哪些"></a>14.Java类加载器有哪些</h3><p>JDK有三个类加载器:</p>
<ol>
<li>bootstrap ClassLoader是ExClassLoader 的父类加载器,默认负责加载%JAVA_HOME%bin下的jar包和class文件</li>
<li>ExClassLoader是AppClassLoader的父类加载器负责加载%JAVA_HOME%&#x2F;bin&#x2F;ext文件夹下的jar包和class文件</li>
<li>AppClassLoader是自定义加载器的父类负责加载classpath下的类文件系统类加载器线程上下文加载器</li>
</ol>
<p>自定义加载器的方法: 继承ClassLoader实现自定义加载器</p>
<h3 id="15-双亲委派模型"><a href="#15-双亲委派模型" class="headerlink" title="15.双亲委派模型"></a>15.双亲委派模型</h3><p><strong>双亲委派模型的执行流程是这样的:</strong> </p>
<p>1、当加载一个类时会先从应用程序类加载器的缓存里查找相应的类如果能找到就返回对象如果找不到就执行下面流程</p>
<p>2、在扩展加载器缓存中查找相应的类如果能找到就返回对象如果找不到就继续下面流程</p>
<p>3、在启动类加载器中查询相应的类如果找到就返回对象如果找不到就继续下面流程</p>
<p>4、在扩展加载器中查找并加载类如果能找到就返回对象并将对象加入到缓存中如果找不到就继续下面流程</p>
<p>5、在应用程序类加载器中查找并加载类如果能找到就返回对象并将对象加入到缓存中如果找不到就返回 ClassNotFound 异常。</p>
<p><strong>加载流程如下图所示:</strong></p>
<p><img src="/pictures/image-20230904161407239.png" alt="image-20230904161407239"></p>
<p>一般“双亲”指的是“父亲”和“母亲”,而在这里“双亲”指的是类加载类先向上找,再向下找的流程就叫做双亲委派模型。</p>
<p><strong>双亲委派模型的好处</strong></p>
<ol>
<li>主要是为了安全性避免用户自己编写的类动他替换java的一些核心类比如String</li>
<li>同时避免了类的重复加载因为jvm中区分不同类不仅仅是根据类名相同的class文件被不同的ClassLoader加载就是不同的两个类</li>
</ol>
<h3 id="16-Java中的异常体系"><a href="#16-Java中的异常体系" class="headerlink" title="16.Java中的异常体系"></a>16.Java中的异常体系</h3><ol>
<li>Java中所有异常都来自顶级父类Throwable</li>
<li>Throwable下面有两个子类Exception和Error</li>
<li>Error是程序无法处理的错误一旦出现这个错误程序将被迫停止运行Exception不会导致程序停止</li>
<li>Exception有分为两个部分RunTimeException运行时异常和CheckedException检查异常</li>
<li>RunTimeException常常发生在程序运行过程中会导致程序当前线程执行失败。CheckedException常常发生在程序编译过程中会导致程序编译不通过。</li>
</ol>
<h3 id="17-GC如何判断对象可以被回收"><a href="#17-GC如何判断对象可以被回收" class="headerlink" title="17.GC如何判断对象可以被回收"></a>17.GC如何判断对象可以被回收</h3><ul>
<li>引用计数法每一个对象有一个引用计数属性新增一个引用计数加1引用释放减1计数为0时可以回收。java中没有使用这个方法原因可能会出现A引用了BB又引用了A这时就算他们都不再使用了但是因为他们互相引用计数器&#x3D;1永远无法被回收</li>
<li>可达性分析法从GC Roots开始向下搜索搜索所走过的路径称为引用链。当一个对象到GC Roots没有任何引用链相连时则证明此对象是不可用的那么虚拟机就可以判断是可回收对象。</li>
</ul>
<h3 id="18-线程的生命周期,线程有哪些状态"><a href="#18-线程的生命周期,线程有哪些状态" class="headerlink" title="18.线程的生命周期,线程有哪些状态"></a>18.线程的生命周期,线程有哪些状态</h3><p>线程通常有五种状态:创建、就绪、运行、阻塞、死亡状态</p>
<p>阻塞又分为三种情况:等待阻塞、同步阻塞、其他阻塞</p>
<ol>
<li>新建状态:新创建了一个线程对象</li>
<li>就绪状态线程对象创建后其他线程调用了该对象的start()方法。该线程位于可运行线程池中变得可运行等待获取CPU的使用权</li>
<li>运行状态就绪状态的线程获取了CPU执行了程序代码</li>
<li>阻塞状态阻塞状态是线程因为某种原因放弃了CPU使用权暂时停止运行。直到线程进入就绪状态才有机会转到运行状态</li>
<li>死亡状态线程执行完了或者因为异常退出了run()方法,该线程结束生命周期</li>
</ol>
<h3 id="19-sleep-wait-join-yield-的区别"><a href="#19-sleep-wait-join-yield-的区别" class="headerlink" title="19.sleep(),wait(),join(),yield()的区别"></a>19.sleep(),wait(),join(),yield()的区别</h3><p><strong>sleep(),wait()的区别</strong></p>
<ol>
<li>sleep()是Thread类的静态本地方法wait()是Object类的本地方法</li>
<li>sleep()不会释放锁把锁带着进入冻结状态wait会释放锁</li>
<li>sleep方法不依赖于同步器synchronized但是wait需要依赖synchronized关键字</li>
<li>sleep不需要被唤醒休眠之后退出阻塞但是wait需要不指定时间需要被别人中断</li>
<li>sleep一般用于当前线程休眠或者轮循暂停操作wait则用于多线程之间的通信</li>
<li>sleep会让出cpu执行时间且强制上下文切换而wait则不一定wait后可能还是有机会重新竞争到锁继续执行</li>
</ol>
<p><strong>yield()执行后线程直接进入就绪状态马上释放了cpu但是依然保留了cpu的执行资格所有有可能cpu下次进行线程调度还会让这个线程取到执行权</strong></p>
<p><strong>join()执行后线程进入阻塞状态例如在线程B中调用了A的join()那线程B会进入到阻塞队列直到线程A结束或者中断线程</strong></p>
<h3 id="20-说说你对线程安全的理解"><a href="#20-说说你对线程安全的理解" class="headerlink" title="20.说说你对线程安全的理解"></a>20.说说你对线程安全的理解</h3><p>线程安全讲的不是线程安全,应该是<strong>内存安全</strong><strong>堆是共享内存,可以被所有线程访问</strong></p>
<p><strong>线程安全的定义</strong>:当多个线程访问一个对象的时候,如果不用进行<strong>额外的同步控制或者其他的协调操作</strong>,调用这个对象的行为都可以获得<strong>正确的结果</strong>,我们就说这个线程数是安全的。</p>
<p><strong>产生线程安全问题的原因:</strong> 在每个进程的内存空间中都会有一块特殊的公共区域,通常称为堆(内存)。进程内所有线程都可以访问到该区域,这就是造成问题的潜在原因。</p>
<h3 id="21-说说你对守护线程的理解"><a href="#21-说说你对守护线程的理解" class="headerlink" title="21.说说你对守护线程的理解"></a>21.说说你对守护线程的理解</h3><p><strong>守护线程</strong>为非守护线程用户线程提供服务的线程任何一个守护线程都是整个jvm中所有非守护线程的守护线程。</p>
<p><strong>守护线程的作用:</strong></p>
<p>举例GC垃圾回收机制就是一个经典的守护线程当我们的程序不再有任何运行的Thread程序就不会再产生垃圾垃圾回收器也就没事可做所以当垃圾回收线程是jvm上仅剩的线程时垃圾回收线程会自动离开它始终再低级别的状态中运行用于实时监控和管理系统中的可回收资源。</p>
<p><strong>应用场景:</strong></p>
<ol>
<li>为其他的线程提供服务支持情况</li>
<li>或者在任何情况下,程序结束时,这个线程必须正常的且立刻关闭,就可以作为守护线程来使用</li>
</ol>
<h3 id="22-ThreadLocal的原理和使用场景"><a href="#22-ThreadLocal的原理和使用场景" class="headerlink" title="22.ThreadLocal的原理和使用场景"></a>22.ThreadLocal的原理和使用场景</h3><p>同一个线程中通过ThreadLocal存进去的数据在任何位置取出来是一致的</p>
<p><strong>原理</strong></p>
<p>每一个Thread对象均含有一个ThreadLocalMap类型的成员变量threadLocals,它存储<strong>本线程</strong>中所有ThreadLocal对象及对应的值。</p>
<p>当执行set()方法时ThreadLocal首先会获取当前线程对象然后获取当前线程的ThreadLocalMap对象。再以当前ThreadLocal对象为key获取对应的value。</p>
<p>get方法的执行过程类似。ThreadLocal首先会获取当前线程对象然后获取当前线程的ThreadLocalMap对象。再以当前ThreadLocal对象为key获取对应的value。</p>
<p>由于每一条线程均含有各自<strong>私有</strong>的ThreadLocalMap容器这些容器相互独立互不影响因此不会存在线程安全性问题从而无需使用同步机制来保证多条线程访问容器的互斥性。</p>
<p><strong>使用场景</strong></p>
<ol>
<li>在进行对象的跨层传递的时候使用ThreadLocal可以避免多次传递打破层次间的约束</li>
<li>线程间数据隔离</li>
<li>进行事务操作,用于存储事务信息</li>
<li>数据库连接Session会话管理</li>
</ol>
<h3 id="23-ThreadLocal内存泄漏原因怎么避免"><a href="#23-ThreadLocal内存泄漏原因怎么避免" class="headerlink" title="23.ThreadLocal内存泄漏原因怎么避免"></a>23.ThreadLocal内存泄漏原因怎么避免</h3><p><strong>内存泄漏</strong>:不会使用的对象或者变量占用的内存不能被回收,就是内存泄漏(内存泄漏为程序在申请内存后无法释放已申请的内存空间一次内存泄漏的危害可以忽略但内存泄漏堆积后果很严重无论多少内存迟早会被占光导致OOM。)</p>
<p>强引用使用最普遍的引用通过new一个对象具有强应用不会被垃圾回收器回收即使是内存不足。我们想要取消强引用可以显示的将引用赋值为nulljvm在合适的时间就会回收该对象。</p>
<p><strong>ThreadLocal内存泄漏的根源</strong></p>
<p>由于ThreadLocalMap的生命周期和Thread一样长如果没有手动删除对应key就会导致内存泄漏</p>
<p><strong>怎么避免</strong></p>
<ol>
<li>每次使用ThreadLocal都调用它的remove()方法清除数据</li>
<li>将ThreadLocal变量定义成private static,这样就一直村子ThreadLocal的强应用也就能保证任何时候都能通过ThreadLocal的弱引用访问到Entry的value值进而清除掉。</li>
</ol>
<h3 id="24-产生内存泄漏的原因有哪些"><a href="#24-产生内存泄漏的原因有哪些" class="headerlink" title="24.产生内存泄漏的原因有哪些"></a>24.产生内存泄漏的原因有哪些</h3><ol>
<li>资源未关闭或释放导致内存泄露(io资源数据库的连接)</li>
<li>使用 ThreadLocal 造成内存泄露</li>
<li>静态集合类引起内存泄漏如HashMap、LinkedList等等。如果这些容器为静态的那么它们的生命周期与程序一致则容器中的对象在程序结束之前将不能被释放从而造成内存泄漏。生命周期长的对象持有短生命周期对象的引用尽管短生命周期的对象不再使用但是因为长生命周期对象持有它的引用而导致不能被回收。</li>
<li>重写了 finalize() 的类,如果 finalize() 方法重写的不合理或 finalizer 队列无法跟上 Java 垃圾回收器的速度,那么迟早,应用程序会出现 OutOfMemoryError 异常</li>
</ol>
<h3 id="25-并发、并行、串行的区别"><a href="#25-并发、并行、串行的区别" class="headerlink" title="25.并发、并行、串行的区别"></a>25.并发、并行、串行的区别</h3><p>串行在时间上不可能发生重叠,前一个任务没有搞定,下一个任务只能等</p>
<p>并行在时间上是重叠的,两个任务在同一时刻互不干扰的同时执行</p>
<p>并发允许两个任务彼此干扰,同一时间点,只有一个任务运行,交替执行</p>
<h3 id="26-并发的三大特性"><a href="#26-并发的三大特性" class="headerlink" title="26.并发的三大特性"></a>26.并发的三大特性</h3><ul>
<li>原子性是指在在一个操作中CPU不可以在中途暂停然后再调度即不被中断操作要不全部执行完成要不都不执行。</li>
<li>可见性:当多个线程访问同一个变量时,一个线程修改了这个变量的值,其他的线程能够立即看到修改的值。</li>
<li>有序性:虚拟机再进行代码编译的时,对于那些改变顺序之后不会对最终的结果造成影响的代码,虚拟机不一定会按照我们写的代码的顺序来执行,有可能将它们重排序。</li>
</ul>
<h3 id="27-为什么用线程池?解释线程池参数?"><a href="#27-为什么用线程池?解释线程池参数?" class="headerlink" title="27.为什么用线程池?解释线程池参数?"></a>27.为什么用线程池?解释线程池参数?</h3><p><strong>为什么</strong></p>
<ol>
<li>降低资源的消耗;提高线程的利用率,降低创建和销毁现成的消耗</li>
<li>提高响应速度,任务来了,直接有线程可用执行,不是创建线程之后再执行</li>
<li>提高线程的可管理性;线程是稀缺资源,使用线程池可以统一分配调优监控</li>
</ol>
<p><strong>线程池参数</strong></p>
<ul>
<li><code>corePoolSize</code>代表核心线程数,也就是正常情况下创建工作的线程数,这些线程创建之后不会消除,而是一种常驻线程。</li>
<li><code>maxnumPoolSize</code>代表最大线程数,它与核心线程数相对应,表示最大允许被创建的线程数,比如当前任务较多,将核心线程数都用完了,还无法满足要求时,此时就会创建新的线程,但是线程池总数不会超过最大线程数</li>
<li><code>keepAliveTime</code>空闲线程存活时间,当一个可被回收的线程的空闲时间大于keepAliveTime就会被回收; unitkeepAliveTime的时间单位</li>
<li><code>workQueue</code>工作队列,存放待执行任务的队列当提交的任务数超过核心线程数大小后再提交的任务就存放在工作队列任务调度时再从队列中取出任务。它仅仅用来存放被execute()方法提交的Runnable任务。工作队列实现了BlockingQueue接口。</li>
<li><code>threadFactory</code>线程工厂,创建线程的工厂,可以设定线程名、线程编号等。</li>
<li><code>handler</code>拒绝策略,当线程池线程数已满并且工作队列达到限制新提交的任务使用拒绝策略处理。可以自定义拒绝策略拒绝策略需实现RejectedExecutionHandler接口。</li>
</ul>
<h3 id="28-简述线程池的处理流程"><a href="#28-简述线程池的处理流程" class="headerlink" title="28.简述线程池的处理流程"></a>28.简述线程池的处理流程</h3><p><img src="/pictures/image-20230905204135018.png" alt="image-20230905204135018"></p>
<h3 id="29-线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?"><a href="#29-线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?" class="headerlink" title="29.线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?"></a>29.线程池中阻塞队列的作用?为什么是先添加队列而不是先创建最大线程?</h3><p><strong>线程池中阻塞队列的作用?</strong></p>
<p>1、一般的队列只能保证作为一个有限长度的缓冲区如果超出了缓冲长度就无法保留当前的任务了阻塞队列通过阻塞可以保留住当前想要继续入队的任务。</p>
<p>2、阻塞队列可以保证任务队列中没有任务时阻塞获取任务的线程使得线程进入wait状态释放cpu资源。</p>
<p>3、阻塞队列自带阻塞和唤醒的功能不需要额外处理无任务执行时线程池利用阻塞队列的take方法挂起从而维持核心线程的存活不至于一直占着cpu资源。</p>
<p><strong>为什么是先添加队列而不是先创建最大线程?</strong></p>
<p>在创建新线程的时候。是要获取全局锁的,这个时候其它就得阻塞,影响了整体效率。</p>
<p>就好比一个企业里面有10个core正式工的名额最多招10个正式工要是任务超过正式工人数task &gt; core的情况下工厂领导线程池不是首先扩招工人还是这10个人但是任务会稍微的积压一下即先放到队列去代价低10个正式工慢慢干迟早会干完的要是任务还在继续增加超过正式工的加班忍耐极限了队列满了就得招外包帮忙了注意是临时工要是正式工加上外包还是不能完成任务那新来的任务就会被领导拒绝了线程池的拒绝策略</p>
<h3 id="30-线程池中线程复用原理"><a href="#30-线程池中线程复用原理" class="headerlink" title="30.线程池中线程复用原理"></a>30.线程池中线程复用原理</h3><p>线程池将线程和任务解耦线程是线程任务是任务摆脱了之前通过Thread创建线程时的一个线程必须对应一个任务的限制。</p>
<p>在线程池中同一个线程可以从阻塞队列中不断获取新任务来执行其核心原理在于线程池对Thread进行了封装并不是每次执行都会调用Thread.start()来创建新线程而是让每个线程去执行一个“循环任务”在这个“循环任务”中不停检查是否有任务需要被执行如果有则执行也就是调用任务中的run方法将run方法当成一个普通的方法执行通过这种方式只使用固定的线程就将所有任务的run方法串联起来。</p>
<h3 id="31-Spring是什么"><a href="#31-Spring是什么" class="headerlink" title="31.Spring是什么"></a>31.Spring是什么</h3><p>轻量级的开源的j2EE框架。他是一个容器框架用来装javabeanjava对象中间层框架万能胶可以起一个连接作用比如说把struts和hibernate粘合在一起运用可以让我们的企业开发更快、更简洁</p>
<p>Spring是一个轻量级的控制反转(ioc)和面向切面aop的容器框架</p>
<ul>
<li>从大小与开销两方面而言Spring都是轻量级的</li>
<li>通过控制反转(ioc)的技术达到松耦合的目的</li>
<li>提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务进行内聚的开发</li>
<li>包含并管理应用对象bean的配置和生命周期这个意义上是一个容器</li>
<li>将简单的组件配置、组合成复杂的应用,这个意义上是一个框架</li>
</ul>
<h3 id="32-谈谈你对AOP的理解"><a href="#32-谈谈你对AOP的理解" class="headerlink" title="32.谈谈你对AOP的理解"></a>32.谈谈你对AOP的理解</h3><p>系统是由许多不同的组件所组成的,每一个组件各负责一块特定的功能。除了实现自身的核心功能之外,这些组件还经常承担着额外的职责。例如日志、事务管理和安全这样的服务经常融入到自身具有核心业务逻辑的组件中去。这些系统服务经常被称为横切关注点,因为他们会跨域系统的多个组件。</p>
<p>当我们需要将分散的对象引入公共行为的时候OOP则显得无能为力也就是说OOP允许你定义从上到下的关系但并不适合定义从左到右的关系。例如日志功能</p>
<p>AOP将程序中的交叉业务逻辑比如安全、日志、事务封装成一个切面。然后注入到目标对象具体业务逻辑中去。AOP可以对某个对象或者某些功能进行增强比如对象中的方法进行增强可以在执行某个方法之前额外做一些事情在某个方法执行之后额外做一些事情。</p>
<h3 id="33-谈谈你对IOC的理解"><a href="#33-谈谈你对IOC的理解" class="headerlink" title="33.谈谈你对IOC的理解"></a>33.谈谈你对IOC的理解</h3><p>容器概念、控制反转、依赖注入三方面理解</p>
<p><strong>容器概念</strong></p>
<p>ioc容器实际上就是个mapkey、value里面存的就是各种对象在xml里配置bean节点、@Repository、@Service、@Controller在项目启动的时候会读取配置文件路面的bean节点。</p>
<p><strong>控制反转</strong></p>
<p>在没有引入ioc容器之前对象A依赖于对象B那么对象A在初始化或者运行到某一点的时候自己必须主动去创建对象B或者使用已经创建的对象B。无论是创建还是使用对象B控制权都在自己手上。</p>
<p>引入ioc容器之后对象A和对象B之间失去了直接联系。当对象A运行到需要对象B的时候ioc容器会主动创建一个对象B注入到对象A需要的地方。</p>
<p>通过前后的对比不难看出来对象A获得依赖对象B的过程由主动行为变成了被动行为控制权颠倒过来了这就是控制反转这个名称的由来。</p>
<p><strong>依赖注入</strong></p>
<p>“获得依赖对象的过程被反转了”。控制器反转之后获得依赖对象的过程由自身管理变为了由IOC容器主动注入。依赖注入是实现IOC的方法就是由IOC容器在运行期间动态地将某种依赖关系注入到对象之中。</p>
<h3 id="34-BeanFactory和ApplicationContext有什么区别"><a href="#34-BeanFactory和ApplicationContext有什么区别" class="headerlink" title="34.BeanFactory和ApplicationContext有什么区别"></a>34.BeanFactory和ApplicationContext有什么区别</h3><p>ApplicationContext是BeanFactory的子接口</p>
<p>ApplicationContext提供了更完整的功能</p>
<p>1、继承了MessageSource,因此支持国际化</p>
<p>2、统一资源文件的访问方式</p>
<p>3、提供在监听器中注册bean的事件</p>
<p>4、同时加载多个配置文件</p>
<p>5、载入多个有继承关系上下文使得每一个上下文都专注于一个特定的层次比如应用的web层</p>
<h3 id="35-深拷贝和浅拷贝"><a href="#35-深拷贝和浅拷贝" class="headerlink" title="35.深拷贝和浅拷贝"></a>35.深拷贝和浅拷贝</h3><p>深拷贝和浅拷贝就是指对象的拷贝,一个对象中存在两种类型的属性,一种是基本数据类型,一种是实列对象的引用</p>
<ul>
<li>浅拷贝是指,只会拷贝基本数据类型的值,以及实例对象的引用地址,并不会复制一份引用地址所指向的对象,也就是浅拷贝出来的对象,内部的类属性指向的是一个对象</li>
<li>深拷贝是指,既会拷贝基本数据类型的值,也会针对实例对象的引用地址所指向的对象进行复制,深拷贝出来的对象,内部的类执行指向的不是同一个对象</li>
</ul>
<p>举例:A对象中有一个user属性A1拷贝A对象两个user指向同一个对象的话就是浅拷贝反之是深拷贝</p>
<h3 id="36-TCP和UDP有什么区别TCP为什么是三次握手而不是两次"><a href="#36-TCP和UDP有什么区别TCP为什么是三次握手而不是两次" class="headerlink" title="36.TCP和UDP有什么区别TCP为什么是三次握手而不是两次"></a>36.TCP和UDP有什么区别TCP为什么是三次握手而不是两次</h3><p><strong>TCP</strong> Transfer Control Protocol是一种面向连接的、可靠的、传输层通信协议</p>
<ul>
<li>面向连接的,点对点的通信,高可靠,效率比较低、占用系统的资源比较多(类似于打电话)</li>
</ul>
<p><strong>UDP</strong> (User Datagram Protocal) 是一种无连接、不可靠的、传输层通信协议</p>
<ul>
<li>不需要连接、发送方不管接收方有没有准备好,直接发消息;可以进行广播发送的;传输不可靠,有可能会丢失消息;效率比较高;协议比较简单,占用的系统资源少(类似于广播)</li>
</ul>
<p><strong>TCP为什么是三次握手而不是两次</strong></p>
<p>如果是两次握手,可能会造成连接资源浪费的问题</p>
<h3 id="37-JVM中有哪些垃圾回收算法"><a href="#37-JVM中有哪些垃圾回收算法" class="headerlink" title="37.JVM中有哪些垃圾回收算法"></a>37.JVM中有哪些垃圾回收算法</h3><p>MarkSweep标记清除算法</p>
<p>Copying拷贝算法</p>
<p>MarkCompack标记压缩算法</p>
2023-09-26 18:57:45 +08:00
<h3 id="38-集合相关的面试题"><a href="#38-集合相关的面试题" class="headerlink" title="38.集合相关的面试题"></a>38.集合相关的面试题</h3><p> <img src="/pictures/image-20230926110554758.png" alt="image-20230926110554758"></p>
<p><img src="/pictures/image-20230926122104134.png" alt="image-20230926122104134"></p>
<p><img src="/pictures/image-20230926121325686.png" alt="image-20230926121325686"></p>
<p><img src="/pictures/image-20230926121517150.png" alt="image-20230926121517150"></p>
<p><img src="/pictures/image-20230926122420662.png" alt="image-20230926122420662"></p>
<p><img src="/pictures/image-20230926122546930.png" alt="image-20230926122546930"></p>
<p><img src="/pictures/image-20230926133043725.png" alt="image-20230926133043725"></p>
<p><img src="/pictures/image-20230926133301807.png" alt="image-20230926133301807"></p>
2023-09-22 21:57:28 +08:00
<h2 id="二-框架篇相关面试题"><a href="#二-框架篇相关面试题" class="headerlink" title="二.框架篇相关面试题"></a>二.框架篇相关面试题</h2><h3 id="1-Spring-Bean的生命周期"><a href="#1-Spring-Bean的生命周期" class="headerlink" title="1.Spring Bean的生命周期"></a>1.Spring Bean的生命周期</h3><p><strong>1.创建前准备阶段</strong></p>
<p>这个阶段主要是在开始Bean加载之前从Spring上下文和相关配置中解析并查找Bean有关的配置内容比如<code>init-method</code>-容器在初始化bean时调用的方法、<code>destory-method</code>容器在销毁Bean时调用的方法。以及BeanFactoryPostProcessor这类的bean加载过程中的前置和后置处理。这些类或者配置其实是Spring提供给开发者用来实现Bean加载过程中的扩展机制在很多和Spring集成的中间件经常使用比如Dubbo。</p>
<p><strong>2.创建实例阶段</strong></p>
<p>这个阶段主要是通过反射来创建Bean的实例对象并且扫描和解析Bean声明的一些属性。</p>
<p><strong>3.依赖注入阶段</strong></p>
<p>在这个阶段会检测被实例化的Bean是否存在其他依赖如果存在其他依赖就需要对这些被依赖Bean进行注入。比如通过<code>@Autowired</code>、@Setter等依赖注入的配置。在这个阶段还会触发一些扩展的调用比如常见的扩展类BeanPostProcessors用来实现Bean初始化前后的回调、InitializingBean类这个类有一个afterPropertiesSet()方法给属性赋值、还有BeanFactoryAware等等。</p>
<p><strong>4.容器缓存阶段</strong></p>
<p>容器缓存阶段主要是把Bean保存到IoC容器中缓存起来到了这个阶段Bean就可以被开发者使用了。这个阶段涉及到的操作常见的有<code>init-method</code>这个属性配置的方法会在这个阶段调用。比如BeanPostProcessors方法中的后置处理器方法postProcessAfterInitialization也是在这个阶段触发的。</p>
<p><strong>5.销毁实例阶段</strong></p>
<p>这个阶段是完成Spring应用上下文关闭时将销毁Spring上下文中所有的Bean。如果Bean实现了DisposableBean接口或者配置了<code>destory-method</code>属 性,将会在这个阶段被调用。</p>
2023-09-26 18:57:45 +08:00
<p>实例化 -&gt; 属性赋值 -&gt; 初始化 -&gt; 销毁</p>
2023-09-22 21:57:28 +08:00
<h3 id="2-Spring框架中的单例Bean是线程安全的吗"><a href="#2-Spring框架中的单例Bean是线程安全的吗" class="headerlink" title="2.Spring框架中的单例Bean是线程安全的吗"></a>2.Spring框架中的单例Bean是线程安全的吗</h3><p>不是线程安全的!</p>
<p>Sping中Bean默认是单例模式的框架中并没有对Bean进行多线程的封装处理。</p>
<p>线程安全这个问题要从单例与原型Bean分别进行说明。</p>
<p><strong>「原型Bean」</strong>对于原型Bean,每次创建一个新对象也就是线程之间并不存在Bean共享自然是不会有线程安全的问题。</p>
<p><strong>「单例Bean」</strong>对于单例Bean,所有线程都共享一个单例实例Bean,因此是存在资源的竞争。</p>
<p>如果单例Bean,是一个无状态Bean也就是线程中的操作不会对Bean的成员执行<strong>「查询」</strong>以外的操作那么这个单例Bean是线程安全的。比如Spring mvc 的 Controller、Service、Dao等这些Bean大多是无状态的只关注于方法本身。</p>
<h3 id="3-Spring-Bean作用域"><a href="#3-Spring-Bean作用域" class="headerlink" title="3.Spring Bean作用域"></a>3.Spring Bean作用域</h3><p>Spring 的 bean 作用域scope类型有5种</p>
<p>1、singleton:单例,默认作用域。</p>
<p>2、prototype:原型,每次创建一个新对象。</p>
<p>3、request:请求每次Http请求创建一个新对象适用于WebApplicationContext环境下。</p>
<p>4、session:会话,同一个会话共享一个实例,不同会话使用不用的实例。</p>
<p>5、global-session:全局会话,所有会话共享一个实例。</p>
<h3 id="4-Spring框架中用到了哪些设计模式"><a href="#4-Spring框架中用到了哪些设计模式" class="headerlink" title="4.Spring框架中用到了哪些设计模式"></a>4.Spring框架中用到了哪些设计模式</h3><ol>
<li>简单工厂由一个工厂类根据传入的参数动态决定应该创建哪一个产品类。Spring中的BeanFactory就是简单工厂模式的体现根据传入的一个唯一的标识来获得Bean对象但是否在传入参数后创建还是传入参数前创建这个要根据具体情况来定。</li>
<li>工厂方法实现了FactoryBean接口的bean是一类叫做factory的bean.其特点是spring会在使用getBean()调用获得该bean时会自动调用该bean的getObject()方法所以返回的不是factory这个bean,而是这个bean.getObject()方法的返回值。</li>
<li>单例模式保证一个类仅有一个实例并提供一个访问它的全局访问点。spring对单例的实现spring中的单例模式完成了后半句话即提供了全局访问点BeanFactory但没有从构造器级别去控制单例这时因为spring管理的是任意的java对象。</li>
<li>适配器模式spring中定义了一个适配接口使得每一种Controller有一种对应的适配器实现类让适配器代替controller执行响应的方法。这样扩展controller时只需要增加一个适配类就完成了springMvc的扩展了。</li>
<li>装饰器模式动态地给一个对象增加一些额外的职责。就增加功能来说Decorator模式相比生成子类更为灵活。spring中用到的装饰器模式在类名上有两种表现一是类名中含有wrapper另一种时类名中含有Decorator.</li>
<li>动态代理切面在应用运行的时刻被织入。一般情况下在织入切面时AOP容器会为目标对象动态地创建一个代理对象。SpringAOP就是以这种方式织入切面的。 织入:把切面应用到目标对象并创建新代理对象的过程。</li>
<li>观察者模式Spring的事件驱动模型使用的是观察者模式spring中observer模式常用的地方是listener的实现。</li>
<li>策略模式:spring框架的资源访问Resource接口。该接口提供了更强的资源访问能力spring框架本身大量使用了Resource接口来访问底层资源。</li>
</ol>
<h3 id="5-spring中事务实现方和原理式以及隔离级别"><a href="#5-spring中事务实现方和原理式以及隔离级别" class="headerlink" title="5.spring中事务实现方和原理式以及隔离级别"></a>5.spring中事务实现方和原理式以及隔离级别</h3><p><strong>实现方式</strong></p>
<p>在使用Spring框架时可以有两种使用事务的方式一种是编程式一种是申明式的@Transactional注解就是申明式的。</p>
<p>首先事务这个概念是数据库层面的Spring只是基于数据库中的事务进行了扩展以及提供了一些能让程序员更加方便操作事务的方式。比如我们可以通过在某个方法上增加@Transactional注解就可以开启事务这个方法中所有的sql都会在一个事务中执行统一成功失败。</p>
<p><strong>原理</strong></p>
<p>在一个方法上加了@Transactional注解后Spring会基于这个类生成一个代理对象会将这个代理对象作为bean,当在使用这个代理对象的方法时,如果这个方法存在@Transactional注解那么代理逻辑会先把事务的自动提价设置为false,然后再去执行原本的业务逻辑方法,如果执行业务逻辑方法没有异常,那么代理逻辑中就会将事务进行提交,如果执行业务逻辑方法出现了异常,那么则会将事务进行回滚。当然,针对哪些异常回滚事务是可以配置的,可以利用@Transactional注解中的rollbackFor属性进行配置默认情况下会对RuntimeException和Error进行回滚。</p>
<p><strong>隔离级别</strong></p>
<p>spring的事务隔离级别就是数据库的隔离级别外加一个默认级别</p>
<ol>
<li>read uncommitted(未提交读)</li>
<li>read committed(提交读、不可重复读)</li>
<li>repeatable read (可重复读)</li>
<li>serializable(可串行化)</li>
</ol>
<p>数据库设置的隔离级别会被spring的配置覆盖</p>
<h3 id="6-Spring事务传播机制"><a href="#6-Spring事务传播机制" class="headerlink" title="6.Spring事务传播机制"></a>6.Spring事务传播机制</h3><p>多个事务方法相互调用的时,事务是如何在这些方法间传播</p>
<p>方法A是一个事务的方法方法A执行过程中调用了方法B那么方法B有无事务以及方法B对事务的要求不同都会对方法A的事务具体执行造成影响同时方法A的事务对方法B的事务执行也有影响这种影响具体是什么就由两个方法所定义的事务传播类型所决定。</p>
<p><strong>REQUIRED</strong>(Spring默认的事务传播类型)如果当前没有事务,则自己创建一个事务,如果当前存在事务,则加入这个事务</p>
<p><strong>SUPPORTS</strong>:当前存在事务,则加入当前事务,如果当前没有事务,就以非事务方法执行</p>
<p><strong>MANDATORY</strong>:当前存在事务,则加入当前事务,如果当前的事务不存在,则抛出异常</p>
<p><strong>REQUIRES_NEW</strong>:创建一个新事务,如果存在当前事务,则挂起该事务</p>
<p><strong>NOT_SUPPORTED</strong>:以非事务方式执行,如果当前存在事务,则挂起当前事务</p>
<p><strong>NEVER</strong>:不使用事务,如果当前事务存在,则抛出异常</p>
<p><strong>NESTED</strong>:如果当前事务存在则在嵌套事务中执行否则REQUIRED的操作一样开启一个事务</p>
<h3 id="7-Spring事务什么时候会失效"><a href="#7-Spring事务什么时候会失效" class="headerlink" title="7.Spring事务什么时候会失效"></a>7.Spring事务什么时候会失效</h3><p>Spring事务原理是AOP进行了切面增强那么失效的根本原因是这个AOP不起作用了常见情况有如下几种</p>
<ol>
<li>发生自调用类里面使用this调用本类的方法此时这个this对象不是代理类而是UserService对象本身</li>
<li>方法不是public的,非要在非public上使用事务可以开启Aspectj代理模式</li>
<li>数据库不支持事务例如使用的MyISAM存储引擎</li>
<li>没有被spring管理</li>
<li>异常被吃掉事务不会回滚或者抛出的异常没有定义默认为RuntimeException</li>
</ol>
<h3 id="8-什么是bean的自动装配有哪些方式"><a href="#8-什么是bean的自动装配有哪些方式" class="headerlink" title="8.什么是bean的自动装配有哪些方式"></a>8.什么是bean的自动装配有哪些方式</h3><p>autowire属性有五种装配的方式</p>
<ul>
<li>no 缺省情况下自动配置是通过“ref”属性手动设定</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--手动装配以value或ref的方式明确指定属性值都是手动装配。 需要通过ref属性来连接bean--&gt;</span></span><br></pre></td></tr></table></figure>
<ul>
<li>byName-根据bean的属性名称进行自动装配</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--Cutomer的属性名称是personSpring会将bean id为person的bean通过setter方法进行自动装配--&gt;</span></span><br><span class="line">&lt; bean id=“cutomer” class=“com.xxx.xxx.Cutomer” autowire=“byName”/&gt;</span><br><span class="line">&lt; bean id=“person” class=“com.xxx.xxx.Person”/&gt;</span><br></pre></td></tr></table></figure>
<ul>
<li>byType-根据bean的类型进行自动装配</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--Cutomer的属性person的类型为PersonSpirng会将Person类型通过setter方法进行自动装配--&gt;</span></span><br><span class="line">&lt; bean&gt; id=“cutomer” class=“com.xxx.xxx.Cutomer” autowire=“byType”/&gt;</span><br><span class="line">&lt; bean&gt; id=“person” class=“com.xxx.xxx.Person”/&gt;</span><br></pre></td></tr></table></figure>
<ul>
<li>constructor-类似byType不过是应用于构造器的参数。如果一个bean与构造器参数的类型形<br>同,则进行自动装配,否则导致异常</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--Cutomer构造函数的参数person的类型为PersonSpirng会将Person类型通过构造方法进行自动装配--&gt;</span></span><br><span class="line">&lt; bean&gt; id=“cutomer” class=“com.xxx.xxx.Cutomer” autowire=“construtor”/&gt;</span><br><span class="line">&lt; bean&gt; id=“person” class=“com.xxx.xxx.Person”/&gt;</span><br></pre></td></tr></table></figure>
<ul>
<li>autodetect-如果有默认的构造器则通过constructor方式进行自动装配否则使用byType方式 进行自动装配</li>
</ul>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--如果有默认的构造器则通过constructor方式进行自动装配否则使用byType方式进行自动装配--&gt;</span></span><br></pre></td></tr></table></figure>
<h3 id="9-Spring-Boot、SpringMVC和Spring有什么区别"><a href="#9-Spring-Boot、SpringMVC和Spring有什么区别" class="headerlink" title="9.Spring Boot、SpringMVC和Spring有什么区别"></a>9.Spring Boot、SpringMVC和Spring有什么区别</h3><p><strong>Spring</strong>是一个IOC容器用来管理Bean,使用依赖注入实现控制反转可以很方便的整合各种框架提供AOP机制弥补OOP的代码重复问题更方便将不同方法中的共同处理抽取成切面自动注入给方法执行比如日志、异常等</p>
<p><strong>SpringMvc</strong>是spring对web框架的一个解决方案提供了一个总的前端控制器Servlet用来接受请求然后定义了一套路由策略url到handle的映射及适配执行handle将handle结果使用视图解析技术生成视图展现给前端</p>
<p><strong>SpringBoot</strong>是Spring提供的一个快速开发工具包让程序员更方便、更快速的开发spring + springmvc应用简化了配置约定了默认配置整合了一系列的解决方案starter机制,redis、mongodb、es可以开箱即用</p>
<h3 id="10-SpringMVC的工作流程"><a href="#10-SpringMVC的工作流程" class="headerlink" title="10.SpringMVC的工作流程"></a>10.SpringMVC的工作流程</h3><ol>
<li>用户发送请求到前端控制器DispatcherServlet</li>
<li>DispatcherServlet收到请求调用HandlerMapping处理器映射器</li>
<li>处理器映射器找到具体的处理器可以根据xml配置、注解进行查找,生成处理器及处理器拦截器如果有则生成一并返回给DispatcherServlet</li>
<li>DispatcherServlet调用HandlerAdapter处理器适配器</li>
<li>HandlerAdapter调用具体的处理器controller也叫后端控制器</li>
<li>Controller执行完成返回ModelAndView</li>
<li>HandlerAdapter将Controller执行结果ModelAndView返回给DispatcherServlet</li>
<li>DispatcherServlet将ModelAndView传给ViewReslover视图解析器</li>
<li>ViewReslover解析后返回具体view</li>
<li>DispatcherServlet根据view进行渲染视图即将模型数据填充到视图中</li>
<li>DispatcherServlet响应给用户</li>
</ol>
<p><img src="/pictures/image-20230911141826287.png" alt="image-20230911141826287"></p>
<h3 id="11-SpringMvc中的九大组件"><a href="#11-SpringMvc中的九大组件" class="headerlink" title="11.SpringMvc中的九大组件"></a>11.SpringMvc中的九大组件</h3><p>Handler是用来干活的工具HandlerMapping用于根据需要干的活找到相应的工具HandlerAdapter是使用工具干活的人</p>
<ol>
<li><p><strong>HandlerMapping</strong>是用来查找Handler的。在SpringMVC中会有很多请求每个请求都需要一个Handler处理具体接收到一个请求之后使用哪个Handler进行处理呢这就是HandlerMapping需要做的事。</p>
</li>
<li><p><strong>HandlerAdapter</strong>,从名字上看它就是一个适配器。因为SpringMVC中的Handler可以是任意的形式只要能处理请求就ok但是Servlet需要的处理方法的结构却是固定的都是以request和response为参数的方法。如何让固定的Servlet处理方法调用灵活的Handler来进行处理呢这就是HandlerAdapter要做的事情。</p>
</li>
<li><p><strong>HandlerExceptionResolver</strong>其它组件都是用来干活的。在干活的过程中难免会出现问题出问题后怎么办呢这就需要有一个专门的角色对异常情况进行处理在SpringMVC中就是HandlerExceptionResolver。具体来说此组件的作用是根据异常设置ModelAndView之后再交给render方法进行渲染。</p>
</li>
<li><p><strong>ViewResolverViewResolver</strong>用来将String类型的视图名和Locale解析为View类型的视图。View是用来渲染页面的也就是将程序返回的参数填入模板里生成html也可能是其它类型文件。这里就有两个关键问题使用哪个模板用什么技术规则填入参数这其实是ViewResolver主要要做的工作ViewResolver需要找到渲染所用的模板和所用的技术也就是视图的类型进行渲染具体的渲染过程则交由不同的视图自己完成。</p>
</li>
<li><p><strong>RequestToViewNameTranslatorViewName</strong>是根据ViewName查找View但有的Handler处理完后并没有设置View也没有设置ViewName这时就需要从request获取ViewName了如何从request中获取ViewName就是RequestToViewNameTranslator要做的事情了。RequestToViewNameTranslator在Spring MVC容器里只可以配置一个所以所有request到ViewName的转换规则都要在一个Translator里面全部实现。</p>
</li>
<li><p><strong>LocaleResolver</strong>解析视图需要两个参数一是视图名另一个是Locale。视图名是处理器返回的Locale是从哪里来的这就是LocaleResolver要做的事情。LocaleResolver用于从request解析出LocaleLocale就是zh-cn之类表示一个区域有了这个就可以对不同区域的用户显示不同的结果。SpringMVC主要有两个地方用到了Locale一是ViewResolver视图解析的时候二是用到国际化资源或者主题的时候。</p>
</li>
<li><p><strong>ThemeResolver</strong>用于解析主题。SpringMVC中一个主题对应一个properties文件里面存放着跟当前主题相关的所有资源、如图片、css样式等。SpringMVC的主题也支持国际化同一个主题不同区域也可以显示不同的风格。SpringMVC中跟主题相关的类有 ThemeResolver、ThemeSource和Theme。主题是通过一系列资源来具体体现的要得到一个主题的资源首先要得到资源的名称这是ThemeResolver的工作。然后通过主题名称找到对应的主题可以理解为一个配置文件这是ThemeSource的工作。最后从主题中获取资源就可以了。</p>
</li>
<li><p><strong>MultipartResolver</strong>用于处理上传请求。处理方法是将普通的request包装成MultipartHttpServletRequest后者可以直接调用getFile方法获取File如果上传多个文件还可以调用getFileMap得到FileName-&gt;File结构的Map。此组件中一共有三个方法作用分别是判断是不是上传请求将request包装成MultipartHttpServletRequest、处理完后清理上传过程中产生的临时资源。</p>
</li>
<li><p><strong>FlashMapManager</strong>用来管理FlashMap的FlashMap主要用在redirect中传递参数。</p>
</li>
</ol>
<h3 id="12-SpringBoot自动配置原理简答的阐述见下面15条"><a href="#12-SpringBoot自动配置原理简答的阐述见下面15条" class="headerlink" title="12.SpringBoot自动配置原理简答的阐述见下面15条"></a>12.SpringBoot自动配置原理简答的阐述见下面15条</h3><p>自动装配简单来说就是自动把第三方组件的Bean装载到Spring IOC器里面不需要开发人员再去写Bean的装配配置。</p>
<p>在Spring Boot应用里面只需要在启动类加上@SpringBootApplication注解就可以实现自动装配。@SpringBootApplication是一个复合注解真正实现自动装配的注解是@EnableAutoConfiguration。</p>
<p><img src="/pictures/image-20230911195638524.png" alt="image-20230911195638524"></p>
<h3 id="13-MyBatis的优缺点"><a href="#13-MyBatis的优缺点" class="headerlink" title="13.MyBatis的优缺点"></a>13.MyBatis的优缺点</h3><p><strong>优点:</strong></p>
<ol>
<li>基于SQL语句编程相当灵活不会对应用程序或者数据库的现有设计造成任何影响SQL写在XML里解除sql与程序代码的耦合便于统一管理提供XML标签支持编写动态SQL语句并可重用</li>
<li>与JDBC相比减少了50%以上的代码量消除了JDBC大量冗余的代码不需要手动开关连接</li>
<li>很好的与各种数据库兼容因为MyBatis使用JDBC来连接数据库所以只要JDBC支持的数据库MyBatis都支持)</li>
<li>能够与Spring很好的集成</li>
<li>提供映射标签支持对象与数据库的ORM字段关系映射提供对象关系映射标签支持对象关系组件维护</li>
</ol>
<p><strong>缺点:</strong></p>
<p>1.<br> SQL语句的编写工作量较大尤其当字段多、关联表多时对开发人员编写SQL语句的功底有一定要求<br>2. SQL语句依赖于数据库导致数据库移植性差不能随意更换数据库</p>
<h3 id="14-MyBatis中-和-的区别是什么?"><a href="#14-MyBatis中-和-的区别是什么?" class="headerlink" title="14.MyBatis中#{}和${}的区别是什么?"></a>14.MyBatis中#{}和${}的区别是什么?</h3><ol>
<li>功能不同:${} 是直接替换,而 #{} 是预处理</li>
<li>使用场景不同:普通参数使用 #{},如果传递的是 SQL 命令或 SQL 关键字,需要使用 ${},但在使用前一定要做好安全验证</li>
<li>安全性不同:使用 ${} 存在安全问题SQL注入而 #{} 则不存在安全问题</li>
</ol>
<h3 id="15-Spring-Boot自动装配的过程"><a href="#15-Spring-Boot自动装配的过程" class="headerlink" title="15.Spring Boot自动装配的过程"></a>15.Spring Boot自动装配的过程</h3><p><img src="/pictures/image-20230921145126572.png" alt="image-20230921145126572"></p>
<p><strong>整个自动装配的过程是</strong>Spring Boot通过@EnableAutoConfiguration注解开启自动配置加载spring.factories中注册的各AutoConfiguration类当某个AutoConfiguration类满足其注解@Conditional指定的生效条件Starters提供的依赖、配置或Spring容器中是否存在某个Bean等实例化该AutoConfiguration类中定义的Bean组件等并注入Spring容器就可以完成依赖框架的自动配置。</p>
<h2 id="二-Mysql相关面试题"><a href="#二-Mysql相关面试题" class="headerlink" title="二.Mysql相关面试题"></a>二.Mysql相关面试题</h2><h3 id="1-存储引擎InnoDB-与MyISAM-的区别"><a href="#1-存储引擎InnoDB-与MyISAM-的区别" class="headerlink" title="1.存储引擎InnoDB 与MyISAM 的区别"></a>1.存储引擎InnoDB 与MyISAM 的区别</h3><ol>
<li>数据存储的方式不同MyISAM中的数据和索引是分开存储的而InnoDB是把索引和数据存储在同一个文件里面</li>
<li>对于事务的支持不同MyISAM不支持事务而InnoDB支持ACID特性的事务处理</li>
<li>对于锁的支持不同MyISAM只支持表锁而InnoDB可以根据不同的情况支持行锁表锁间隙锁临键锁</li>
<li>MyISAM不支持外键InnoDB支持外键因此基于这些特性我们在实际应用中可以根据不同的场景来选择合适的存储引擎</li>
<li>比如如果需要支持事务那必须要选择InnoDB。如果大部分的表操作都是查询可以选择MyISAM</li>
</ol>
<h3 id="2-索引的基本原理"><a href="#2-索引的基本原理" class="headerlink" title="2.索引的基本原理"></a>2.索引的基本原理</h3><p>原理:把无序的数据变成有序的查询</p>
<ol>
<li>把创建了索引的列的内容进行排序</li>
<li>对排序结果生成倒排表</li>
<li>在倒排表内容上拼上数据地址链</li>
<li>在查询的时候,先拿到倒排表的内容,再取出数据地址链,从而拿到数据</li>
</ol>
<h3 id="3-索引失效的场景"><a href="#3-索引失效的场景" class="headerlink" title="3.索引失效的场景"></a>3.索引失效的场景</h3><ol>
<li>索引在使用的时候没有遵循最左匹配法则.</li>
<li>模糊查询,如果%号在前面也会导致索引失效。</li>
<li>在添加索引的字段上进行了运算操作或者类型转换也都会导致索引失效。</li>
<li>如果使用了复合索引,中间使用了范围查询,右边的条件索引也会失效</li>
<li>查询的时候发生了类型转换,在查询的时候做了运算的操作和模糊查询也会导致索引失效</li>
</ol>
<h3 id="4-事务的隔离级别有哪些MySQL-的默认隔离级别是什么?"><a href="#4-事务的隔离级别有哪些MySQL-的默认隔离级别是什么?" class="headerlink" title="4.事务的隔离级别有哪些MySQL 的默认隔离级别是什么?"></a>4.事务的隔离级别有哪些MySQL 的默认隔离级别是什么?</h3><p>读未提交Read Uncommitted可能读到其他事务未提交的数据也叫做脏读<br>读已提交Read Committed两次读取结果不一致叫做不可重复读<br>可重复读Repeatable Read是mysql默认的隔离级别每次读取的结果都一样当时可能产生幻读<br>串行化Serializable一般是不会使用的他给每一行读取的数据加锁会导致大量超时和锁竞争的问题<br>Mysql 默认的事务隔离级别是可重复读(Repeatable Read)</p>
<h3 id="5-事务的基本特性"><a href="#5-事务的基本特性" class="headerlink" title="5.事务的基本特性"></a>5.事务的基本特性</h3><p>事务的基本特性ACID分别是</p>
<ol>
<li>A 原子性:一个事务的操作要么全部成功,要么全部失败</li>
<li>C 一致性:数据库从一个一致性的状态转换到另一个一致性的状态</li>
<li>I 隔离性:一个事务的修改在最终提交前,对其他事务是不可见的</li>
<li>D 持久性 一旦事务提交,所做的修改就会永远的保存到数据库中</li>
</ol>
<h3 id="6-怎么处理慢查询"><a href="#6-怎么处理慢查询" class="headerlink" title="6.怎么处理慢查询"></a>6.怎么处理慢查询</h3><p>SQL查询慢的原因</p>
<ol>
<li>查询没有命中索引</li>
<li>查询了不需要的数据列</li>
<li>数据量太大</li>
</ol>
<p>根据上面的原因给出优化的措施</p>
<ol>
<li>分析语句的执行计划,然后获得其使用索引的情况,然后修改语句或者索引,使得语句可以尽可能的命中索引</li>
<li>分析语句,是否查询了不需要的数据列</li>
<li>如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表</li>
</ol>
<h3 id="7-ACID靠什么保证的"><a href="#7-ACID靠什么保证的" class="headerlink" title="7.ACID靠什么保证的"></a>7.ACID靠什么保证的</h3><p>A 原子性由<strong>undo log日志</strong>保证它记录了需要回滚的日志信息事务回滚时撤销已经执行成功的sql</p>
<p>C 一致性由其他的三大特性保证 程序代码要保证业务上的一致性</p>
<p>I 隔离性由<strong>MVCC</strong>来保证</p>
<p>D 持久性由<strong>内存 + redo log</strong> 来保证。Mysql修改数据同时在内存和redo log记录这次操作宕机的时候可以从redo log恢复</p>
<h2 id="三-Redis相关面试题"><a href="#三-Redis相关面试题" class="headerlink" title="三.Redis相关面试题"></a>三.Redis相关面试题</h2><h3 id="1-Redis过期键的删除策略"><a href="#1-Redis过期键的删除策略" class="headerlink" title="1.Redis过期键的删除策略"></a>1.Redis过期键的删除策略</h3><p>redis是key-value数据库我们可以设置redis中缓存的key的过期时间。redis的过期策略就是指当redis中缓存的key过期了redis该如何处理。</p>
<ul>
<li><strong>惰性过期</strong>只有当访问一个key时才会判断该key是否已过期过期则删除。该策略可以最大化地节省CU资源但是对内存非常的不友好。极端地情况可能出现大量地过期key没有再次被访问从而不被清除占用大量内存。</li>
<li>**定期过期:**每隔一定地时间会扫描一定数量地数据库地expires字典中一定数量地key并清除其中已过期的key。该策略是前两者的一个折中方案。通过定时扫描的时间间隔和每次扫描的限定功耗可以在不同情况下使得CPU和内存资源达到最优的平衡效果。</li>
</ul>
<p>在Redis中同时使用了这两种策略</p>
<h3 id="2-Redis的线程模型单线程为什么快"><a href="#2-Redis的线程模型单线程为什么快" class="headerlink" title="2.Redis的线程模型单线程为什么快"></a>2.Redis的线程模型单线程为什么快</h3><p>IO多路复用机制监听多个Socket</p>
<p><strong>单线程快的原因:</strong></p>
<ol>
<li>纯内存操作</li>
<li>核心是基于非阻塞的IO多路复用机制</li>
<li>单线程反而避免了多线程的频繁上下文切换带来的性能问题</li>
</ol>
<h3 id="3-缓存雪崩、缓存穿透、缓存击穿"><a href="#3-缓存雪崩、缓存穿透、缓存击穿" class="headerlink" title="3.缓存雪崩、缓存穿透、缓存击穿"></a>3.缓存雪崩、缓存穿透、缓存击穿</h3><p><strong>缓存雪崩</strong> 缓存在同一时间大面积失效,所以,后面的请求都会落在数据库上,造成数据库短时间内承受大量请求而崩掉。</p>
<p>解决方案:</p>
<ol>
<li>缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生</li>
<li>给每一个缓存数据增加响应的缓存标记,记录缓存是否失效,如果缓存标记失效,则更新数据缓存</li>
<li>缓存预热,启动系统之前先把热点数据放在缓存中去</li>
<li>互斥锁</li>
</ol>
<p><strong>缓存穿透</strong> 缓存和数据库中都没有数据,导致所有的请求都落在数据库上,造成数据库短时间内承受大量请求</p>
<p>解决方案:</p>
<ol>
<li>接口层增加校验如用户鉴权校验id做基础校验id&lt;&#x3D;0的直接拦截掉</li>
<li>从缓存取不到数据在数据库中也没有取到这时也可以将key-value对写为key-null缓存有效时间可以设置短一些如30秒设置太长会导致正常的情况也没法使用。这样可以防止攻击用户反复用同一个id暴力攻击</li>
<li>采用布隆过滤器将所有可能存在的数据哈希到一个足够大的bitmap中一个一定不存在的数据会被这个bitmap拦截掉从而避免了对底层存储系统的查询压力</li>
</ol>
<p><strong>缓存击穿</strong> 缓存中没有但数据库中有的数据(一般是缓存时间到期),这时由于并发用户特别多,同时读缓存没有读到数据,又同时去数据库取数据,引起数据库压力瞬间增大,造成过大压力。和缓存雪崩不同的是,缓存击穿指并发查同一条数据,缓存雪崩是不同数据都过期了,很多数据都查不到从而查数据库。</p>
<p>解决方案:</p>
<ol>
<li>设置热点数据永不过期</li>
<li>加互斥锁</li>
</ol>
<h3 id="4-Redis的数据结构"><a href="#4-Redis的数据结构" class="headerlink" title="4.Redis的数据结构"></a>4.Redis的数据结构</h3><p>Redis支持五种数据类型string字符串hash哈希list列表set无序集合及zset(有序集合)</p>
<p><img src="/pictures/image-20230914154911197.png" alt="image-20230914154911197"></p>
<p><strong>PDF</strong></p>
<div class="row">
<embed src="/pdf/2023最新Java面试题全集.pdf" width="100%" height="550" type="application/pdf">
</div>
2024-06-14 22:00:25 +08:00
</article><div class="tag_share"><div class="post-meta__tag-list"><a class="post-meta__tags" href="/tags/%E9%9D%A2%E8%AF%95/">面试</a></div><div class="post_share"><div class="social-share" data-image="/img/4.png" data-sites="wechat,weibo,qq"></div><link rel="stylesheet" href="/cdn/css/share.min.css" media="print" onload="this.media='all'"><script src="/cdn/js/social-share.min.js" defer></script></div></div><div class="post-reward"><div class="reward-button"><i class="fas fa-qrcode"></i> 打赏</div><div class="reward-main"><ul class="reward-all"><li class="reward-item"><a href="/img/wechat.jpg" target="_blank"><img class="post-qr-code-img" src="/img/wechat.jpg" alt="微信"/></a><div class="post-qr-code-desc">微信</div></li><li class="reward-item"><a href="/img/alipay.jpg" target="_blank"><img class="post-qr-code-img" src="/img/alipay.jpg" alt="支付宝"/></a><div class="post-qr-code-desc">支付宝</div></li></ul></div></div><br/><div id="post-comment"><div class="comment-head"><div class="comment-headline"><i class="far fa-comment-alt fa-fw"></i><span> 评论</span></div></div><div class="comment-wrap"><div><div id="gitalk-container"></div></div></div></div></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="is-center"><div class="avatar-img"><img src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/loading.gif'" alt="avatar"/></div><div class="author-info__name">Jason</div><div class="author-info__description">Debug the World</div></div><div class="card-info-data site-data is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">60</div></a><a href="/tags/"><div class="headline">标签</div><div class="length-num">39</div></a><a href="/categories/"><div class="headline">分类</div><div class="length-num">10</div></a></div><a id="card-info-btn"><i class="fab fa-microsoft"></i><span>Ctrl + D 收藏</span></a><div class="card-info-social-icons is-center"><a class="social-icon" href="https://github.com/JasonsGong" target="_blank" title="Github"><i class="fab fa-github"></i></a><a class="social-icon" href="tencent://AddContact/?fromId=45&amp;fromSubId=1&amp;subcmd=all&amp;uin=2602183349&amp;website=www.oicqzone.com" target="_blank" title="QQ"><i class="fab fa-qq"></i></a><a class="social-icon" href="mailto:2602183349@qq.com" target="_blank" title="Email"><i class="fas fa-envelope-open-text"></i></a><a class="social-icon" href="https://github.com/JasonsGong?tab=repositories" target="_blank" title="代码仓库"><i class="fas fa-database"></i></a></div></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn fa-shake"></i><span>公告</span></div><div class="announcement_content">本网站是静态网站,更新页面资源请使用Ctrl+F5;若网站内文章对你有帮助,请使用Ctrl+D收藏该网站</div></div><div class="sticky_layout"><div class="card-widget" id="card-toc"><div class="item-headline"><i class="fas fa-stream"></i><span>目录</span><span class="toc-percentage"></span></div><div class="toc-content is-expand"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#%E4%B8%80-Java%E5%9F%BA%E7%A1%80%E9%9D%A2%E8%AF%95%E9%A2%98"><span class="toc-text">一.Java基础面试题</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#1-%E8%B0%88%E8%B0%88%E4%BD%A0%E5%AF%B9%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%9A%84%E7%90%86%E8%A7%A3"><span class="toc-text">1.谈谈你对面向对象的理解</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#2-JDK%E3%80%81JRE%E3%80%81JVM%E4%B9%8B%E9%97%B4%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">2.JDK、JRE、JVM之间的区别</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#3-%E5%92%8Cequals%E2%BD%85%E6%B3%95%E7%9A%84%E5%8C%BA%E5%88%AB"><span class="toc-text">3.&#x3D;&#x3D;和equals⽅法的区别</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#4-String-StringBuffer-StringBuilder%E7%9A%84%E5%
2024-01-13 16:32:52 +08:00
function initGitalk () {
var gitalk = new Gitalk(Object.assign({
clientID: '00fb27b1e484536359c2',
clientSecret: 'be41a12281c68b6e228d1a27e8d08aeb91541145',
repo: 'BlogComment',
owner: 'JasonsGong',
admin: ['JasonsGong'],
id: 'c2c14686e4a9990ff65f12ff26164c6f',
updateCountCallback: commentCount
},null))
gitalk.render('gitalk-container')
}
if (typeof Gitalk === 'function') initGitalk()
else {
2024-01-13 17:50:17 +08:00
getCSS('/cdn/css/gitalk.min.css')
getScript('/cdn/js/gitalk.min.js').then(initGitalk)
2024-01-13 16:32:52 +08:00
}
}
function commentCount(n){
let isCommentCount = document.querySelector('#post-meta .gitalk-comment-count')
if (isCommentCount) {
isCommentCount.textContent= n
}
}
if ('Gitalk' === 'Gitalk' || !true) {
if (true) btf.loadComment(document.getElementById('gitalk-container'), loadGitalk)
else loadGitalk()
} else {
function loadOtherComment () {
loadGitalk()
}
}</script></div><script async data-pjax src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script><div id="local-search"><div class="search-dialog"><nav class="search-nav"><span class="search-dialog-title">搜索</span><span id="loading-status"></span><button class="search-close-button"><i class="fas fa-times"></i></button></nav><div class="is-center" id="loading-database"><i class="fas fa-spinner fa-pulse"></i><span> 数据库加载中</span></div><div class="search-wrap"><div id="local-search-input"><div class="local-search-box"><input class="local-search-box--input" placeholder="搜索文章" type="text"/></div></div><br/><div class="no-result" id="local-search-results"></div><div id="local-search-stats-wrap"></div></div></div><div id="search-mask"></div><script src="/js/search/local-search.js"></script></div></div><!-- hexo injector body_end start --><script data-pjax>
2023-09-22 21:57:28 +08:00
function butterfly_swiper_injector_config(){
2024-01-13 22:42:28 +08:00
var parent_div_git = document.getElementById('recent-posts');
2024-06-14 22:00:25 +08:00
var item_html = '<div class="recent-post-item" style="height: auto;width: 100%"><div class="blog-slider swiper-container-fade swiper-container-horizontal" id="swiper_container"><div class="blog-slider__wrp swiper-wrapper" style="transition-duration: 0ms;"><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/19306.html" alt=""><img width="48" height="48" src="/img/1.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-04-21</span><a class="blog-slider__title" href="posts/19306.html" alt="">Docker容器化技术</a><div class="blog-slider__text">Docker</div><a class="blog-slider__button" href="posts/19306.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/47003.html" alt=""><img width="48" height="48" src="/img/5.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-03-10</span><a class="blog-slider__title" href="posts/47003.html" alt="">常用正则表达式大全</a><div class="blog-slider__text">正则表达式</div><a class="blog-slider__button" href="posts/47003.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/20683.html" alt=""><img width="48" height="48" src="/img/8.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-05</span><a class="blog-slider__title" href="posts/20683.html" alt="">Linux中开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/20683.html" alt="">详情 </a></div></div><div class="blog-slider__item swiper-slide" style="width: 750px; opacity: 1; transform: translate3d(0px, 0px, 0px); transition-duration: 0ms;"><a class="blog-slider__img" href="posts/63333.html" alt=""><img width="48" height="48" src="/img/10.png" alt="" onerror="this.src=https://unpkg.zhimg.com/akilar-candyassets/image/loading.gif; this.onerror = null;"/></a><div class="blog-slider__content"><span class="blog-slider__code">2023-06-03</span><a class="blog-slider__title" href="posts/63333.html" alt="">开发环境的搭建</a><div class="blog-slider__text">环境搭建</div><a class="blog-slider__button" href="posts/63333.html" alt="">详情 </a></div></div></div><div class="blog-slider__pagination swiper-pagination-clickable swiper-pagination-bullets"></div></div></div>';
2024-01-13 22:42:28 +08:00
if (parent_div_git !== null && typeof parent_div_git !== 'undefined') {
parent_div_git.insertAdjacentHTML("afterbegin",item_html)
}
2023-09-22 21:57:28 +08:00
}
var elist = 'undefined'.split(',');
var cpage = location.pathname;
2023-10-28 10:47:20 +08:00
var epage = 'all';
2023-09-22 21:57:28 +08:00
var flag = 0;
for (var i=0;i<elist.length;i++){
if (cpage.includes(elist[i])){
flag++;
}
}
if ((epage ==='all')&&(flag == 0)){
butterfly_swiper_injector_config();
}
else if (epage === cpage){
butterfly_swiper_injector_config();
}
2024-01-13 22:10:58 +08:00
</script><script defer src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper.min.js"></script><script defer data-pjax src="https://npm.elemecdn.com/hexo-butterfly-swiper/lib/swiper_init.js"></script><!-- hexo injector body_end end --></body></html>