面试题汇总
程序员文章站
2022-04-18 08:26:36
...
面试题汇总,略有不足,仅供参考,后期会逐渐完善
一、Java 基础
1.JDK 和 JRE 有什么区别?
答:JDK是开发工具包,包括JRE,编译器,其他工具。
JRE是java运行环境。
2.== 和 equals 的区别是什么?
答:==比较的是地址值是否相等,
Equals比较的是内容是否相等。
3.两个对象的 hashCode相同,则 equals也一定为 true,对吗?
答:不一定。HashCode返回的是该对象的哈希码值,equals返回两个对象是否相等。
4.final 在 java 中有什么作用?
答:final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。 内部类要访问局部变量,局部变量必须定义成final类型
5.java 中的 Math.round(-1.5) 等于多少?
答:-1
6.String 属于基础的数据类型吗?
答:final是引用类型,底层是char数组实现的。
7.java 中操作字符串都有哪些类?它们之间有什么区别?
答: String :适用于不频繁的操作
StringBuffer:线程安全,效率低,适用于多线程。
StringBuilder:线程不安全,效率高,适用于单线程
执行效率:StringBuilder>StringBuffer>String
8.String str="i"与 String str=new String("i")一样吗?
答:不一样,不是同一个对象
9.如何将字符串反转?
答:https://blog.csdn.net/cghu1201/article/details/78490934
https://blog.csdn.net/qq_24309787/article/details/100989861
https://www.cnblogs.com/lanseyitai1224/p/6955609.html
第一种 通过String类的charAt()的方法来获取字符串中的每一个字符,然后将其拼接为一个新的字符串。
第二种 通过String的toCharArray()方法可以获得字符串中的每一个字符串并转换为字符数组,然后用一个空的字符串从后向前一个个的拼接成新的字符串。
第三种 通过StringBuiler的reverse()的方法,最快的方式。
第四种 通过递归的方式,其实有以上的就可以了,但是还是说一下递归,实在是应为这个感觉高大上一点而已。
10.String 类的常用方法都有那些?
答:int length()得到一个字符串的字符个数
Byte[] getByte()将一个字符串转换成字节数组
Boolean equals()判断两个字符串的内容是否一样
11.抽象类必须要有抽象方法吗?
答:可以是私有的,也可以是非抽象的方法,所以不是必须。
12.普通类和抽象类有哪些区别?
1抽象类不能被实例
2抽象类不能有构造函数,抽象方法不能声明为静态
3抽象类可以有抽象方法
4抽象类的抽象方法必须被非抽象子类继承
13.抽象类能使用 final 修饰吗?
答:不能,抽象类中的抽象方法是未来继承之后的重写方法,而用final修饰的类无法被继承。
14.接口和抽象类有什么区别?
15.java 中 IO 流分为几种?
答:分两种,字节流和字符流。(或者答四种)
字节流:InputStream,OutputStream
字符流:InputStreamReader, OutputStreamWriter
16.BIO、NIO、AIO 有什么区别?
答:不会,答案又臭又长。面试也不碰到过。提供两篇文章
https://blog.csdn.net/u010310183/article/details/81700405
https://blog.csdn.net/meism5/article/details/89469101
17.Files的常用方法都有哪些?
答:https://www.cnblogs.com/cocoxu1992/p/10460994.html
二、容器
18.java 容器都有哪些?
答:list,set,map。
19.Collection 和 Collections 有什么区别?
答:Collection是一个接口,Collections是一个类。
Collection是集合类的*接口,其派生了两个子接口 Set 和 List。
Collections则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。
20.List、Set、Map 之间的区别是什么?
答:List:有顺序的集合,可以包含重复元素。
Set:不包含重复元素的集合。
Map:可以把键(key)映射到值(value)的对象,键不能重复。
其他版本答案:
List:
o可以允许重复对象
o可以插入多个null元素
o是一个有序容器
Set:
o不允许重复对象
o只允许一个null元素
o无序容器
Map:
oMap不是Collection的子接口或实现类。Map是一个接口
oMap 的每个Entry都特有两个对象,也就是一个键一个值,Map可能会持有相同的值对象但键对象必须是唯一的
oMap里可以拥有随意个niull值但最多只能有一个null键
21.HashMap 和 Hashtable 有什么区别?
答:Hashtable不允许键和值为null,HashMap允许键和值为null;
Hshtable是多线程,效率低,线程安全,HashMap是单线程,效率高,线程不安全。
22.如何决定使用 HashMap 还是 TreeMap?
答:对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择。
23.说一下 HashMap 的实现原理?
24.说一下 HashSet 的实现原理?
答:shSet是基于HashMap实现的,HashSet 底层使用HashMap来保存所有元素,
因此HashSet 的实现比较简单,相关HashSet 的操作,基本上都是直接调用底层HashMap的相关方法来完成,HashSet不允许有重复的值,并且元素是无序的。
25.ArrayList 和 LinkedList 的区别是什么?
答:1. ArrayList底层是数组,LinkedList底层是链表。
2. ArrayList占内存小,LinkedList占内存比较大。因为LinkedList为每一个节点储存了两个引用,一个指向前一个元素,一个指向后一个元素;
3.LinkedList的插入,添加,删除操作速度更快
26.如何实现数组和 List 之间的转换?
27.ArrayList 和 Vector 的区别是什么?
答:(1)同步性:Vector是线程安全的,用synchronized实现线程安全,而ArrayList是线程不安全的,如果只有一个线程会访问到集合,那最好使用ArrayList,因为它不考虑线程安全,效率会高些;如果有多个线程会访问到集合,那最好是使用Vector,因为不需要我们再去考虑和编写线程安全的代码。
(2)数据容量增长:二者都有一个初始容量大小,采用线性连续存储空间,当存储的元素的个数超过了容量时,就需要增加二者的存储空间,Vector增长原来的一倍,ArrayList增加原来的0.5倍。
28.Array 和 ArrayList 有何区别?
答:1.Array可以包含基本类型和对象类型,ArrayList只包含对象;
2.Array是固定的,ArrayList是多态;
3.ArrList提供了更多的方法和特性,比如addAll();
29.在 Queue 中 poll和 remove有什么区别?
答:Queue 中 remove() 和 poll()都是用来从队列头部删除一个元素。
在队列元素为空的情况下,remove() 方法会抛出NoSuchElementException异常,poll() 方法只会返回 null 。
30.哪些集合类是线程安全的?
答:vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
31.迭代器 Iterator 是什么?
答:第一种说法:为了方便的处理集合中的元素,Java中出现了一个对象,该对象提供了一些方法专门处理集合中的元素.例如删除和获取集合中的元素.该对象就叫做迭代器(Iterator).
32.Iterator 怎么使用?有什么特点?
答:使用方法:https://blog.csdn.net/meism5/article/details/89917376
特点:迭代器---不必知道序列底层是怎么实现的,就可以利用迭代器来访问一个序列。
33.Iterator 和 ListIterator 有什么区别?
答:1.Iterator可以遍历set和list集合,ListIterator只可以遍历list集合;
2.前者只能前向遍历,后者可以前向遍历,也可以后向遍历;
3.ListIterator实现Iterator接口和其他功能。
34.怎么确保一个集合不能被修改?
答:Collections.unmodifiableList(List)
Collections.unmodifiableMap(Map)
Collections.unmodifiableSet(Set)
以上返回的集合对象都是不可修改的,调用修改方法会抛出异常UnsupportedOperationException
三、多线程
35.并行和并发有什么区别?
并发在单核和多核都可存在,就是同一时间有多个可以执行的进程。但是在单核中同一时刻只有一个进程获得CPU,虽然宏观上你认为多个进程都在进行
并行是指同一时间多个进程在微观上都在真正的执行,这就只有在多核的情况下了
36.线程和进程的区别?
线程:是程序执行流的最小单元,是系统独立调度和分配CPU(独立运行)的基本单位
进程:是资源分配的基本单位。一个进程包括多个线程
区别:地址空间、资源拥有
1.线程与资源分配无关,它属于某一个进程,并与进程内的其他线程一起共享进程的资源
2.每个进程都有自己一套独立的资源(数据),供其内的所有线程共享
3.不论是大小,开销线程要更“轻量级”
4.一个进程内的线程通信比进程之间的通信更快速,有效。(因为共享变量)
37.守护线程是什么?
答:守护线程是个服务线程,服务于其他线程典型案例:垃圾回收线程
java里线程分2种:
1、守护线程,比如垃圾回收线程,就是最典型的守护线程。
2、用户线程,就是应用程序里的自定义线程。
详细查看:https://www.cnblogs.com/nongzihong/p/10510696.html
38.创建线程有哪几种方式?
答:第一种:继承Thread类;
第二种:实现Runable接口
第三种:通过Callable和Future创建线程(没见过)
39.说一下 runnable 和 callable 有什么区别?
答:runnable 没有返回值,callable 可以拿到有返回值,callable 可以看作是 runnable 的补充。
40.线程有哪些状态?
答:创建、就绪、运行、阻塞、死亡
41.sleep 和 wait 有什么区别?
sleep() 可以在任何地方使用
wait() 只能在同步方法或同步块中使用
sleep方法没有释放锁,而wait方法释放了锁
链接:https://blog.csdn.net/qq_38998213/article/details/89503556
42.notify和 notifyAll有什么区别?
notify是唤醒某个线程
notifyAll是唤醒所有暂停线程
43.线程的 run和 start有什么区别?
run() 相当于线程的任务处理逻辑的入口方法
start() 的作用是启动相应的线程
(补充):启动一个线程是调用start()方法,使线程就绪状态,以后可以被调度为运行状态,一个线程必须关联一些具体的执行代码, run()方法是该线程所关联的执行代码。
44.创建线程池有哪几种方式?
newSingleThreadExecutor():它的特点在于工作线程数目被限制为 1,操作一个*的工作队列,所以它保证了所有任务的都是被顺序执行,最多会有一个任务处于活动状态,并且不允许使用者改动线程池实例,因此可以避免其改变线程数目;
newCachedThreadPool():它是一种用来处理大量短时间工作任务的线程池,具有几个鲜明特点:它会试图缓存线程并重用,当无缓存线程可用时,就会创建新的工作线程;如果线程闲置的时间超过 60 秒,则被终止并移出缓存;长时间闲置时,这种线程池,不会消耗什么资源。其内部使用 SynchronousQueue 作为工作队列;
newFixedThreadPool(int nThreads):重用指定数目(nThreads)的线程,其背后使用的是*的工作队列,任何时候最多有 nThreads 个工作线程是活动的。这意味着,如果任务数量超过了活动队列数目,将在工作队列中等待空闲线程出现;如果有工作线程退出,将会有新的工作线程被创建,以补足指定的数目 nThreads;
newSingleThreadScheduledExecutor():创建单线程池,返回 ScheduledExecutorService,可以进行定时或周期性的工作调度;
newScheduledThreadPool(int corePoolSize):和newSingleThreadScheduledExecutor()类似,创建的是个 ScheduledExecutorService,可以进行定时或周期性的工作调度,区别在于单一工作线程还是多个工作线程;
newWorkStealingPool(int parallelism):这是一个经常被人忽略的线程池,Java 8 才加入这个创建方法,其内部会构建ForkJoinPool,利用Work-Stealing算法,并行地处理任务,不保证处理顺序;
ThreadPoolExecutor():是最原始的线程池创建,上面1-3创建方式都是对ThreadPoolExecutor的封装。
45.线程池都有哪些状态?
RUNNING:这是最正常的状态,接受新的任务,处理等待队列中的任务。
SHUTDOWN:不接受新的任务提交,但是会继续处理等待队列中的任务。
STOP:不接受新的任务提交,不再处理等待队列中的任务,中断正在执行任务的线程。
TIDYING:所有的任务都销毁了,workCount 为 0,线程池的状态在转换为 TIDYING 状态时,会执行钩子方法 terminated()。
TERMINATED:terminated()方法结束后,线程池的状态就会变成这个。
46.线程池中 submit和 execute方法有什么区别?
execute():只能执行 Runnable 类型的任务。
submit():可以执行 Runnable 和 Callable 类型的任务
补充:Callable 类型的任务可以获取执行的返回值,而 Runnable 执行无返回值。
47.在 java 程序中怎么保证多线程的运行安全?
方法一:使用安全类,比如 Java. util. concurrent 下的类。
方法二:使用自动锁 synchronized。
方法三:使用手动锁 Lock。
Lock lock = new ReentrantLock();
lock.lock();
try {
System. out. println("获得锁");
} catch (Exception e) {
// TODO: handle exception
} finally {
System. out. println("释放锁");
lock. unlock();
}
48.多线程锁的升级原理是什么?
答案:不会。答案又丑又长,自己百度。
49.什么是死锁?
个人答案:两个线程都在等待对方先完成,从而造成程序的停滞状态;
复制答案:当线程 A 持有独占锁a,并尝试去获取独占锁 b 的同时,线程 B 持有独占锁 b,并尝试获取独占锁 a 的情况下,就会发生 AB 两个线程由于互相持有对方需要的锁,而发生的阻塞现象,我们称为死锁。
50.怎么防止死锁?
答:
尽量使用 tryLock(long timeout, TimeUnit unit)的方法(ReentrantLock、ReentrantReadWriteLock),设置超时时间,超时可以退出防止死锁。
尽量使用 Java. util. concurrent 并发类代替自己手写锁。
尽量降低锁的使用粒度,尽量不要几个功能用同一把锁。
尽量减少同步的代码块。
个人答案:1.加锁顺序,线程按照一定顺序加锁;
2.加锁时间,超时可以退出防止死锁;
3.死锁检测
51.ThreadLocal 是什么?有哪些使用场景?
答:ThreadLocal 是线程本地存储,在每个线程中都创建了一个 ThreadLocalMap 对象,每个线程可以访问自己内部 ThreadLocalMap 对象内的 value。
经典的使用场景是:为每个线程分配一个 JDBC 连接 Connection。这样就可以保证每个线程的都在各自的 Connection 上进行数据库的操作,不会出现 A 线程关了 B线程正在使用的 Connection; 还有 Session 管理 等问题。
原文链接:https://blog.csdn.net/meism5/article/details/90413860
52.说一下 synchronized 底层实现原理?
53.synchronized 和 volatile 的区别是什么?
54.synchronized 和 Lock 有什么区别?
55.synchronized 和 ReentrantLock 区别是什么?
56.说一下 atomic 的原理?
四、反射
57.什么是反射?
答:在Java里面一个类有两种状态--编译和运行状态,通常我们需要获取这个类的信息都是在编译阶段获得的,也就是直接点出来或者new出来,可是如果需要在类运行的阶段获得Java的类的信息的话,就需要用到Java的反射。
58.什么是 java 序列化?什么情况下需要序列化?
答:序列化就是把java对象转换为字节序列的方法。
把对象的字节序列化到永久的保存到硬盘中
在网络上传递对象的字节序列
59.动态代理是什么?有哪些应用?
答:动态代理是运行时动态生成代理类。
动态代理指的是可以任意控制任意对象的执行过程
o本来应该自己做的事情,因为没有某种原因不能直接做,只能请别人代理做。被请的人就是代理
o比如春节买票回家,由于没有时间,只能找票务中介来买,这就是代理模式
应用:Spring 的 AOP
60.怎么实现动态代理?
答:
如果底层是接口采用JDK动态代理
如果底层是类采用cglib动态代理
五、对象拷贝
61.为什么要使用克隆?
62.如何实现对象克隆?
63.深拷贝和浅拷贝区别是什么?
六、Java Web
64.jsp 和 servlet 有什么区别?
答:
JSP侧重视图,Sevlet主要用于控制逻辑。
Servlet中没有内置对象 。
JSP中的内置对象都是必须通过HttpServletRequest对HttpServletResponse对象以及HttpServlet对象得到。
65.jsp 有哪些内置对象?作用分别是什么?
答:
JSP共有以下9个内置的对象:
request 用户端请求,此请求会包含来自GET/POST请求的参数
response 网页传回用户端的回应
pageContext 网页的属性是在这里管理
session 与请求有关的会话期
application servlet 正在执行的内容
out 用来传送回应的输出
config servlet的构架部件
page JSP网页本身
exception 针对错误网页,未捕捉的例外
66.说一下 jsp 的 4 种作用域?
答:所谓“作用域”就是“信息共享的范围”,也就是说一个信息能够在多大的范围内有效。
链接:https://blog.csdn.net/koches/article/details/7785438
67.session 和 cookie 有什么区别?
答:
存储位置不同:session 存储在服务器端;cookie 存储在浏览器端。
安全性不同:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中
68.说一下 session 的工作原理?
69.如果客户端禁止 cookie 能实现 session 还能用吗?
答:
一般默认情况下,在会话中,服务器存储 session 的 sessionid 是通过 cookie 存到浏览器里。
如果浏览器禁用了 cookie,浏览器请求服务器无法携带 sessionid,服务器无法识别请求中的用户身份,session失效。但是可以通过其他方法在禁用 cookie 的情况下,可以继续使用session。
1.通过url重写,把 sessionid 作为参数追加的原 url 中,后续的浏览器与服务器交互中携带 sessionid 参数。
2.服务器的返回数据中包含 sessionid,浏览器发送请求时,携带 sessionid 参数。
3.通过 Http 协议其他 header 字段,服务器每次返回时设置该 header 字段信息,浏览器中 js 读取该 header 字段,请求服务器时,js设置携带该 header 字段。
原文链接:https://blog.csdn.net/meism5/article/details/90414108
70.spring mvc 和 struts 的区别是什么?
71.如何避免 sql 注入?
答:
使用预处理 PreparedStatement。
使用正则表达式过滤掉字符中的特殊字符。
72.什么是 XSS 攻击,如何避免?
73.什么是 CSRF 攻击,如何避免?
七、异常
74.throw 和 throws 的区别?
throw:
1)throw语句用在方法体内,表示抛出异常,由方法体内的语句处理。
2)throw是具体向外抛出异常的动作,所以它抛出的是一个异常实例,执行throw一定是抛出了某种异常。
throws:
1)throws语句是用在方法声明后面,表示如果抛出异常,由该方法的调用者来进行异常的处理。
2)throws主要是声明这个方法会抛出某种类型的异常,让它的使用者要知道需要捕获的异常的类型。
3)throws表示出现异常的一种可能性,并不一定会发生这种异常。
75.final、finally、finalize 有什么区别?
1)final:用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,被其修饰的类不可继承。
2)finally:异常处理语句结构的一部分,表示总是执行。
3)finalize:Object类的一个方法,在垃圾回收器执行的时候会调用被回收对象的此方法,可以覆盖此方法,提供垃圾收集时的其他资源回收,例如关闭文件等。该方法更像是一个对象生命周期的临终方法,当该方法被系统调用则代表该对象即将“死亡”,但是需要注意的是,我们主动行为上去调用该方法并不会导致该对象“死亡”,这是一个被动的方法(其实就是回调方法),不需要我们调用。
76.try-catch-finally 中哪个部分可以省略?
答:try-catch-finally 其中 catch 和 finally 都可以被省略,但是不能同时省略,也就是说有 try 的时候,必须后面跟一个 catch 或者 finally
https://blog.csdn.net/meism5/article/details/90414167
77.try-catch-finally 中,如果 catch 中 return 了,finally 还会执行吗?
答:一定会, catch 中 return会等finally中的代码执行完之后才会执行
78.常见的异常类有哪些?
1)java.lang.NullPointerException 空指针异常;出现原因:调用了未经初始化的对象或者是不存在的对象。
2)java.lang.ClassNotFoundException 指定的类找不到;出现原因:类的名称和路径加载错误;通常都是程序试图通过字符串来加载某个类时可能引发异常。
3)java.lang.NumberFormatException 字符串转换为数字异常;出现原因:字符型数据中包含非数字型字符。
4)java.lang.IndexOutOfBoundsException 数组角标越界异常,常见于操作数组对象时发生。
5)java.lang.IllegalArgumentException 方法传递参数错误。
6)java.lang.ClassCastException 数据类型转换异常。
7)java.lang.NoClassDefFoundException 未找到类定义错误。
8)SQLException SQL异常,常见于操作数据库时的SQL语句错误。
9)java.lang.InstantiationException实例化异常。
10)java.lang.NoSuchMethodException 方法不存在异常。
八、网络
79.http 响应码 301 和 302 代表的是什么?有什么区别?
答:
301表示网页永久性转移到另一个地址
302表示临时性转移
区别:
o301是永久的重定向,搜索引擎在抓取新内容的同时也将旧的网址替换为重定向之后的网址
o302重定向是临时的重定向,搜索引擎抓取新的内容而保留旧的网址
另外补充:
80.forward 和 redirect 的区别?
答:
1.转发是浏览器的行为,重定向是客户端的行为;
2.转发特点:一次请求,浏览器地址不变,浏览的是自己web资源,传输数据不会丢失;
3.重定向特点:两次请求,浏览器地址发生改变,可以访问自己web之外的资源,传输数据会丢失;
复制答案:
forward 是服务器的内部重定向
redirect 是服务器收到请求后发送一个状态头给客户,客户将在重新请求一次
81.简述 tcp 和 udp的区别?
答:
tcp 和 udp 是 OSI 模型中的运输层中的协议。tcp 提供可靠的通信传输,而 udp 则常被用于让广播和细节控制交给应用的通信传输。
两者的区别大致如下:
tcp 面向连接,udp 面向非连接即发送数据前不需要建立链接;
tcp 提供可靠的服务(数据传输),udp 无法保证;
tcp 面向字节流,udp 面向报文;
tcp 数据传输慢,udp 数据传输快
另外补充一题:
RPC与HTTP区别
网络7层协议如图所示.
如图-22所示
图-22
层级关系与对应的协议.
如图-23所示
图-23
区别:
1.RPC是传输层协议(4层).而HTTP协议是应用层协议(7层).
2.RPC协议可以直接调用中立接口,HTTP协议不可以.String
3.RPC通信协议是长链接,HTTP协议一般采用短连接需要3次握手(可以配置长链接添加请求头Keep-Alive: timeout=20).
(长连接,指在一个连接上可以连续发送多个数据包,在连接保持期间,如果没有数据包发送,需要双方发链路检测包。)
4.RPC协议传递数据是加密压缩传输.HTTP协议需要传递大量的请求头信息.
5.RPC协议一般都有注册中心.有丰富的监控机制.
82.tcp 为什么要三次握手,两次不行吗?为什么?
83.说一下 tcp 粘包是怎么产生的?
84.OSI 的七层模型都有哪些?
物理层:利用传输介质为数据链路层提供物理连接,实现比特流的透明传输。
数据链路层:负责建立和管理节点间的链路。
网络层:通过路由选择算法,为报文或分组通过通信子网选择最适当的路径。
传输层:向用户提供可靠的端到端的差错和流量控制,保证报文的正确传输。
会话层:向两个实体的表示层提供建立和使用连接的方法。
表示层:处理用户信息的表示问题,如编码、数据格式转换和加密解密等。
应用层:直接向用户提供服务,完成用户希望在网络上完成的各种工作。
85.get 和 post 请求有哪些区别?
网上答案:
get请求的参数在URL中,而post 请求在请求body中
get请求传参有长度限制,post请求没有长度限制
get请求的参数只能是ASCII码,post请求传参没有这个限制
自己答案: doGet:get方法回把名值对追加在请求的url后面,因为url对字符数目有限制,进而限制了用户在客户端请求的参数值的数目,并且在请求中的参数值是可见的。因此,敏感信息不能用这种方式传递;
doPost:post方法通过把请求参数值放在请求体中来克服get方法的限制,因此,可以发送的参数的数目是没有限制的,最后,通过post请求传递的敏感信息是不可见的。
86.如何实现跨域?
答:
使用CORS(跨站资源共享)技术
使用JSONP
补充知识:https://blog.csdn.net/agoodcoder777/article/details/89716854
87.说一下 JSONP 实现原理?
jsonp是一种轻量级的数据交换格式。
jsonp:JSON with Padding,它是利用script标签的 src 连接可以访问不同源的特性,加载远程返回的“JS 函数”来执行的。
补充知识:http://www.bejson.com/knownjson/aboutjsonp/
九、设计模式
88.说一下你熟悉的设计模式?
单例模式:保证被创建一次,节省系统开销。
工厂模式(简单工厂、抽象工厂):解耦代码。
观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。
模版方法模式:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。(解决代码重复问题)
状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。
89.简单工厂和抽象工厂有什么区别?
简单工厂:用来生产同一等级结构中的任意产品,对于增加新的产品,无能为力。
工厂方法:用来生产同一等级结构中的固定产品,支持增加任意产品。
抽象工厂:用来生产不同产品族的全部产品,对于增加新的产品,无能为力;支持增加产品族
十、Spring/Spring MVC
90.为什么要使用 spring?
答:spring是一个开源框架,是个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架
方便结构简化开发
AOP编码的支持
声明式事物的支持
方便程序的测试
方便集成各种优势框架
降低Java EE API 的使用难度
91.解释一下什么是 aop?
答:
自己答案:Aop是面向切面编程,在面向对象编程(oop)思想中,我们将事务纵向抽成一个个的对象,在面向切面编程中,我们将一个个的对象某些类似的方面横向抽成一个切面,对这个切面进行一些如权限控制、事务管理,记录日志等公用操作处理的过程就是面向切面编程的思想。AOP底层是动态代理,如果是接口采用JDK动态代理,如果是类采用CGLIB方式实现动态代理。
复制答案:AOP即面向切面编程,是OOP编程的有效补充。使用AOP技术,可以将一些系统性相关的编程工作,独立提取出来,独立实现,然后通过切面切入进系统。从而避免了在业务逻辑的代码中混入很多的系统相关的逻辑——比如权限管理,事物管理,日志记录等等。
AOP分为静态AOP和动态AOP:
静态AOP是指AspectJ实现的AOP,他是将切面代码直接编译到Java类文件中。
动态AOP是指将切面代码进行动态织入实现的AOP,JDK动态代理。
92.解释一下什么是 ioc?
答:ioc是“控制反转”思想,即将创建对象的权力交给spring容器容器管理。
93.spring 有哪些主要模块?
答:core模块、aop模块、data access模块、web模块、test模块
spring core:框架的最基础部分,提供 ioc 和依赖注入特性。
spring context:构建于 core 封装包基础上的 context 封装包,提供了一种框架式的对象访问方法。
spring dao:Data Access Object 提供了JDBC的抽象层。
spring aop:提供了面向切面的编程实现,让你可以自定义拦截器、切点等。
spring Web:提供了针对 Web 开发的集成特性,例如文件上传,利用 servlet listeners 进行 ioc 容器初始化和针对 Web 的 ApplicationContext。
spring Web mvc:spring 中的 mvc 封装包提供了 Web 应用的 Model-View-Controller(MVC)的实现。
94.spring 常用的注入方式有哪些?
答:@Required,@Autowired,@Qualifier 错误,这是注解方式
答案:详细解析:https://blog.csdn.net/a909301740/article/details/78379720
构造方法注入
setter注入
基于注解注入
95.spring 中的 bean 是线程安全的吗?
答:
spring 中的 bean 默认是单例模式,spring 框架并没有对单例 bean 进行多线程的封装处理。
实际上大部分时候 spring bean 无状态的(比如 dao 类),所有某种程度上来说 bean 也是安全的,但如果 bean 有状态的话(比如 view model 对象),那就要开发者自己去保证线程安全了,最简单的就是改变 bean 的作用域,把“singleton”变更为“prototype”,这样请求 bean 相当于 new Bean()了,所以就可以保证线程安全了。
有状态就是有数据存储功能。
无状态就是不会保存数据。
96.spring 支持几种 bean 的作用域?
答:singleton、prototype、request、session、globalSession五中作用域。
singleton:spring ioc 容器中只存在一个 bean 实例,bean 以单例模式存在,是系统默认值;
prototype:每次从容器调用 bean 时都会创建一个新的示例,既每次 getBean()相当于执行 new Bean()操作;
Web 环境下的作用域:
orequest:每次 http 请求都会创建一个 bean;
osession:同一个 http session 共享一个 bean 实例;
oglobal-session:用于 portlet 容器,因为每个 portlet 有单独的 session,globalsession 提供一个全局性的 http session
97.spring 自动装配 bean 有哪些方式?
答:可分为四种:
byName:按照bean的属性名称来匹配要装配的bean
byType:按照bean的类型来匹配要装配的bean
constructor:按照bean的构造器入参的类型来进行匹配
autodetect(自动检测):先使用constructor进行装配,如果不成功就使用byType来装配
98.spring 事务实现方式有哪些?
答:
声明式事务:声明式事务也有两种实现方式,基于 xml 配置文件的方式和注解方式(在类上添加 @Transaction 注解)。
编码方式:提供编码的形式管理和维护事务。
99.说一下 spring 的事务隔离?(感觉不考,简单看看就好)
答:
spring 有五大隔离级别,默认值为 ISOLATION_DEFAULT(使用数据库的设置),其他四个隔离级别和数据库的隔离级别一致:
ISOLATION_DEFAULT:用底层数据库的设置隔离级别,数据库设置的是什么我就用什么;
ISOLATIONREADUNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读);
ISOLATIONREADCOMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读),SQL server 的默认级别;
ISOLATIONREPEATABLEREAD:可重复读,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读),MySQL 的默认级别;
ISOLATION_SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了
100.说一下 spring mvc 运行流程?
答:
spring mvc 先将请求发送给 DispatcherServlet。
DispatcherServlet 查询一个或多个 HandlerMapping,找到处理请求的 Controller。
DispatcherServlet 再把请求提交到对应的 Controller。
Controller 进行业务逻辑处理后,会返回一个ModelAndView。
Dispathcher 查询一个或多个 ViewResolver 视图解析器,找到 ModelAndView 对象指定的视图对象。
视图对象负责渲染返回给客户端
第二种答案:
1. SpringMVC的工作原理(2017-11-13-lyq)
a. 用户向服务器发送请求,请求被springMVC前端控制器DispatchServlet捕获;
b. DispatcherServle对请求URL进行解析,得到请求资源标识符(URL),然后根据该URL调用HandlerMapping
将请求映射到处理器HandlerExcutionChain;
c. DispatchServlet根据获得Handler选择一个合适的HandlerAdapter适配器处理;
d. Handler对数据处理完成以后将返回一个ModelAndView()对象给DisPatchServlet;
e. Handler 返回的 ModelAndView()只是一个逻辑视图并不是一个正式的视图,DispatcherSevlet 通过
ViewResolver试图解析器将逻辑视图转化为真正的视图View;
h. DispatcherServle 通过 model 解析出 ModelAndView()中的参数进行解析最终展现出完整的 view 并返回给
客户端;
101.spring mvc 有哪些组件?
答:
前置控制器 DispatcherServlet
映射控制器 HandlerMapping
处理器 Controller
模型和视图 ModelAndView
视图解析器 ViewResolver
aaa@qq.com 的作用是什么?
答:将 http 请求映射到相应的类/方法上
aaa@qq.com 的作用是什么?
答:@Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,通过@Autowired 的使用来消除 set/get 方法
十一、Spring Boot/Spring Cloud
104.什么是 spring boot?
答:Spring Boot是一个构建在Spring框架顶部的项目。它提供了一种更简单、更快捷的方法来设置、配置和运行简单和基于Web的应用程序。
105.为什么要用 spring boot?
答:
配置简单
独立运行
自动装配
无代码生成和 xml 配置
提供应用监控
易上手
提升开发效率
106.spring boot 核心配置文件是什么?
spring boot 核心的两个配置文件:
bootstrap (. yml 或者 . properties):boostrap 由父 ApplicationContext 加载的,比 applicaton 优先加载,且 boostrap 里面的属性不能被覆盖
application (. yml 或者 . properties):用于 spring boot 项目的自动化配置
107.spring boot 配置文件有哪几种类型?它们有什么区别?
配置文件有 . properties 格式和 . yml 格式,它们主要的区别是书法风格不同。
. properties 配置如下:
spring. RabbitMQ. port=5672
. yml 配置如下:
spring:
RabbitMQ:
port: 5672
. yml 格式不支持 @PropertySource 注解导入
108.spring boot 有哪些方式可以实现热部署?
答:
使用 devtools 启动热部署,添加 devtools 库,在配置文件中把 spring. devtools. restart. enabled 设置为 true
使用 Intellij Idea 编辑器,勾上自动编译或手动重新编译
109.jpa 和 hibernate 有什么区别?
答:jpa 全称 Java Persistence API,是 Java 持久化接口规范,hibernate 属于 jpa 的具体实现。
110.什么是 spring cloud?
答:spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署
111.spring cloud 断路器的作用是什么?
答:在分布式架构中,断路器模式的作用也是类似的,当某个服务单元发生故障(类似用电器发生短路)之后,通过断路器的故障监控(类似熔断保险丝),向调用方返回一个错误响应,而不是长时间的等待。这样就不会使得线程因调用故障服务被长时间占用不释放,避免了故障在分布式系统中的蔓延
112.spring cloud 的核心组件有哪些?
答:
Eureka:服务注册于发现
Feign:基于动态代理机制,根据注解和选择的机器,拼接请求 url 地址,发起请求
Ribbon:实现负载均衡,从一个服务的多台机器中选择一台
Hystrix:提供线程池,不同的服务走不同的线程池,实现了不同服务调用的隔离,避免了服务雪崩的问题
Zuul:网关管理,由 Zuul 网关转发请求给对应的服务
十二、Hibernate
113.为什么要使用 hibernate?
114.什么是 ORM 框架?
115.hibernate 中如何在控制台查看打印的 sql 语句?
116.hibernate 有几种查询方式?
117.hibernate 实体类可以被定义为 final 吗?
118.在 hibernate 中使用 Integer 和 int 做映射有什么区别?
119.hibernate 是如何工作的?
120.get和 load的区别?
121.说一下 hibernate 的缓存机制?
122.hibernate 对象有哪些状态?
123.在 hibernate 中 getCurrentSession 和 openSession 的区别是什么?
124.hibernate 实体类必须要有无参构造函数吗?为什么?
十三、Mybatis
125.mybatis 中 #{}和 ${}的区别是什么?
答:
1.#是占位符,会对sql进行预编译,相当于?;$是做sql拼接,是字符替换,有sql注入的隐患;
2.#不需要关注数据类型,mybatis自动实现数据类型转换;¥必须自己判断数据类型;
126.mybatis 有几种分页方式?
第一种说法:
答:四种,分别是数组、sql语句,拦截器和RowBounds分页功能。
详情查看一:https://blog.csdn.net/u010667011/article/details/83819277
详情查看二:https://www.cnblogs.com/aeolian/p/9229149.html
第二种说法::
答:两种,分页方式:逻辑分页和物理分页。
逻辑分页: 使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索。
物理分页: 自己手写 SQL 分页或使用分页插件 PageHelper,去数据库查询指定条数的分页数据的形式。
127.RowBounds 是一次性查询全部结果吗?为什么?
答:
RowBounds 表面是在“所有”数据中检索数据,其实并非是一次性查询出所有数据,因为 MyBatis 是对 jdbc 的封装,在 jdbc 驱动中有一个 Fetch Size 的配置,它规定了每次最多从数据库查询多少条数据,假如你要查询更多数据,它会在你执行 next()的时候,去查询更多的数据。就好比你去自动取款机取 10000 元,但取款机每次最多能取 2500 元,所以你要取 4 次才能把钱取完。只是对于 jdbc 来说,当你调用 next()的时候会自动帮你完成查询工作。这样做的好处可以有效的防止内存溢出。
128.mybatis 逻辑分页和物理分页的区别是什么?
答:
逻辑分页是一次性查询很多数据,然后再在结果中检索分页的数据。这样做弊端是需要消耗大量的内存、有内存溢出的风险、对数据库压力较大。
物理分页是从数据库查询指定条数的数据,弥补了一次性全部查出的所有数据的种种缺点,比如需要大量的内存,对数据库查询压力较大等问题。
129.mybatis 是否支持延迟加载?延迟加载的原理是什么?
答:
MyBatis 支持延迟加载,设置 lazyLoadingEnabled=true 即可。
延迟加载的原理的是调用的时候触发加载,而不是在初始化的时候就加载信息。比如调用 a. getB(). getName(),这个时候发现 a. getB() 的值为 null,此时会单独触发事先保存好的关联 B 对象的 SQL,先查询出来 B,然后再调用 a. setB(b),而这时候再调用 a. getB(). getName() 就有值了,这就是延迟加载的基本原理。
130.说一下 mybatis 的一级缓存和二级缓存?
答:
一级缓存:基于 PerpetualCache 的 HashMap 本地缓存,它的声明周期是和 SQLSession 一致的,有多个 SQLSession 或者分布式的环境中数据库操作,可能会出现脏数据。当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认一级缓存是开启的。
二级缓存:也是基于 PerpetualCache 的 HashMap 本地缓存,不同在于其存储作用域为 Mapper 级别的,如果多个SQLSession之间需要共享缓存,则需要使用到二级缓存,并且二级缓存可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现 Serializable 序列化接口(可用来保存对象的状态)。
开启二级缓存数据查询流程:二级缓存 -> 一级缓存 -> 数据库。
缓存更新机制:当某一个作用域(一级缓存 Session/二级缓存 Mapper)进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear。
131.mybatis 和 hibernate 的区别有哪些?(感觉很少很少考,可以忽略)
答:
灵活性:MyBatis 更加灵活,自己可以写 SQL 语句,使用起来比较方便。
可移植性:MyBatis 有很多自己写的 SQL,因为每个数据库的 SQL 可以不相同,所以可移植性比较差。
学习和使用门槛:MyBatis 入门比较简单,使用门槛也更低。
二级缓存:hibernate 拥有更好的二级缓存,它的二级缓存可以自行更换为第三方的二级缓存。
链接:https://blog.csdn.net/weixin_42620326/article/details/90813529
132.mybatis 有哪些执行器(Executor)?
答:
Mybatis有三种基本的Executor执行器: SimpleExecutor、ReuseExecutor R、BatchExecutor。
SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。
ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。
BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。
作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。
133.mybatis 分页插件的实现原理是什么?
134.mybatis 如何编写一个自定义插件?
十四、RabbitMQ
135.rabbitmq 的使用场景有哪些?
答:
场景1:单发送单接收
使用场景:简单的发送与接收,没有特别的处理。
场景2:单发送多接收
使用场景:一个发送端,多个接收端,如分布式的任务派发。为了保证消息发送的可靠性,不丢失消息,使消息持久化了。同时为了防止接收端在处理消息时down掉,只有在消息处理完成后才发送ack消息。
场景3:Publish/Subscribe
使用场景:发布、订阅模式,发送端发送广播消息,多个接收端接收。
场景4:Routing (按路线发送接收)
使用场景:发送端按routing key发送消息,不同的接收端按不同的routing key接收消息。
场景5:Topics (按topic发送接收)
使用场景:发送端不只按固定的routing key发送消息,而是按字符串“匹配”发送,接收端同样如此。
参考链接:https://blog.csdn.net/dreamhai/article/details/81774998
https://blog.csdn.net/WuLex/article/details/79111211
136.rabbitmq 有哪些重要的角色?
137.rabbitmq 有哪些重要的组件?
138.rabbitmq 中 vhost 的作用是什么?
139.rabbitmq 的消息是怎么发送的?
140.rabbitmq 怎么保证消息的稳定性?
141.rabbitmq 怎么避免消息丢失?
142.要保证消息持久化成功的条件有哪些?
143.rabbitmq 持久化有什么缺点?
144.rabbitmq 有几种广播类型?
145.rabbitmq 怎么实现延迟消息队列?
146.rabbitmq 集群有什么用?
147.rabbitmq 节点的类型有哪些?
148.rabbitmq 集群搭建需要注意哪些问题?
149.rabbitmq 每个节点是其他节点的完整拷贝吗?为什么?
150.rabbitmq 集群中唯一一个磁盘节点崩溃了会发生什么情况?
151.rabbitmq 对集群节点停止顺序有要求吗?
十五、Kafka
152.kafka 可以脱离 zookeeper 单独使用吗?为什么?
153.kafka 有几种数据保留的策略?
154.kafka 同时设置了 7 天和 10G 清除数据,到第五天的时候消息达到了 10G,这个时候 kafka 将如何处理?
155.什么情况会导致 kafka 运行变慢?
156.使用 kafka 集群需要注意什么?
十六、Zookeeper
157.zookeeper 是什么?
答:
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。
158.zookeeper 都有哪些功能?
答:
为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。
159.zookeeper 有几种部署模式?
160.zookeeper 怎么保证主从节点的状态同步?
161.集群中为什么要有主节点?
162.集群中有 3 台服务器,其中一个节点宕机,这个时候 zookeeper 还可以使用吗?
答:可以运行。
163.说一下 zookeeper 的通知机制?
十七、MySql
164.数据库的三范式是什么?
答:
第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项。
第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
第三范式:任何非主属性不依赖于其它非主属性。
165.一张自增表里面总共有 7 条数据,删除了最后 2 条数据,重启 mysql 数据库,又插入了一条数据,此时 id 是几?
答:
表类型如果是 MyISAM ,那 id 就是 8。
表类型如果是 InnoDB,那 id 就是 6。
166.如何获取当前数据库版本?
答:使用 select version() 获取当前 MySQL 数据库版本。
select version()
另外,在dos命令启动mysql的时候也显示版本信息。
167.说一下 ACID (事物的四个特性)是什么?
Atomicity(原子性):一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
168.char 和 varchar 的区别是什么?
答:
char(n) :固定长度类型,比如订阅 char(10),当你输入"abc"三个字符的时候,它们占的空间还是 10 个字节,其他 7 个是空字节。
chat 优点:效率高;缺点:占用空间;适用场景:存储密码的 md5 值,固定长度的,使用 char 非常合适。
varchar(n) :可变长度,存储的值是每个值占用的字节再加上一个用来记录其长度的字节的长度。
总结:从空间上考虑 varcahr 比较合适;从效率上考虑 char 比较合适,二者使用需要权衡
169.float 和 double 的区别是什么?
答:
float 最多可以存储 8 位的十进制数,并在内存中占 4 字节。
double 最可可以存储 16 位的十进制数,并在内存中占 8 字节。
170.mysql 的内连接、左连接、右连接有什么区别?
答:
内连接关键字:inner join;左连接:left join;右连接:right join。 内连接是把匹配的关联数据显示出来;左连接是左边的表全部显示出来,右边的表显示出符合条件的数据;右连接正好相反
171.mysql 索引是怎么实现的?
答:
索引是满足某种特定查找算法的数据结构,而这些数据结构会以某种方式指向数据,从而实现高效查找数据。 具体来说 MySQL 中的索引,不同的数据引擎实现有所不同,但目前主流的数据库引擎的索引都是 B+ 树实现的,B+ 树的搜索效率,可以到达二分法的性能,找到数据区域之后就找到了完整的数据结构了,所有索引的性能也是更好的
172.怎么验证 mysql 的索引是否满足需求?
答:
使用 explain 查看 SQL 是如何执行查询语句的,从而分析你的索引是否满足需求。
explain 语法:
explain select * from table where type=1
173.说一下数据库的事务隔离?
答:
MySQL 的事务隔离是在 MySQL. ini 配置文件里添加的,在文件的最后添加:
transaction-isolation = REPEATABLE-READ
可用的配置值:READ-UNCOMMITTED、READ-COMMITTED、REPEATABLE-READ、SERIALIZABLE。
READ-UNCOMMITTED:未提交读,最低隔离级别、事务未提交前,就可被其他事务读取(会出现幻读、脏读、不可重复读)。
READ-COMMITTED:提交读,一个事务提交后才能被其他事务读取到(会造成幻读、不可重复读)。
REPEATABLE-READ:可重复读,默认级别,保证多次读取同一个数据时,其值都和事务开始时候的内容是一致,禁止读取到别的事务未提交的数据(会造成幻读)。
SERIALIZABLE:序列化,代价最高最可靠的隔离级别,该隔离级别能防止脏读、不可重复读、幻读。
脏读 :表示一个事务能够读取另一个事务中还未提交的数据。比如,某个事务尝试插入记录 A,此时该事务还未提交,然后另一个事务尝试读取到了记录 A。
不可重复读 :是指在一个事务内,多次读同一数据。
幻读 :指同一个事务内多次查询返回的结果集不一样。比如同一个事务 A 第一次查询时候有 n 条记录,但是第二次同等条件下查询却有 n+1 条记录,这就好像产生了幻觉。发生幻读的原因也是另外一个事务新增或者删除或者修改了第一个事务结果集里面的数据,同一个记录的数据内容被修改了,所有数据行的记录就变多或者变少了。
174.说一下 mysql 常用的引擎?
答:
InnoDB 引擎:InnoDB 引擎提供了对数据库 acid 事务的支持,并且还提供了行级锁和外键的约束,它的设计的目标就是处理大数据容量的数据库系统。MySQL 运行的时候,InnoDB 会在内存中建立缓冲池,用于缓冲数据和索引。但是该引擎是不支持全文搜索,同时启动也比较的慢,它是不会保存表的行数的,所以当进行 select count(*) from table 指令的时候,需要进行扫描全表。由于锁的粒度小,写操作是不会锁定全表的,所以在并发度较高的场景下使用会提升效率
MyIASM 引擎:MySQL 的默认引擎,但不提供事务的支持,也不支持行级锁和外键。因此当执行插入和更新语句时,即执行写操作的时候需要锁定这个表,所以会导致效率会降低。不过和 InnoDB 不同的是,MyIASM 引擎是保存了表的行数,于是当进行 select count(*) from table 语句时,可以直接的读取已经保存的值而不需要进行扫描全表。所以,如果表的读操作远远多于写操作时,并且不需要事务的支持的,可以将 MyIASM 作为数据库引擎的首选
175.说一下 mysql 的行锁和表锁?
答:
MyISAM 只支持表锁,InnoDB 支持表锁和行锁,默认为行锁
表级锁:开销小,加锁快,不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发量最低
行级锁:开销大,加锁慢,会出现死锁。锁力度小,发生锁冲突的概率小,并发度最高
176.说一下乐观锁和悲观锁?
答:
乐观锁:每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在提交更新的时候会判断一下在此期间别人有没有去更新这个数据
悲观锁:每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻止,直到这个锁被释放
数据库的乐观锁需要自己实现,在表里面添加一个 version 字段,每次修改成功值加 1,这样每次修改的时候先对比一下,自己拥有的 version 和数据库现在的 version 是否一致,如果不一致就不修改,这样就实现了乐观锁
177.mysql 问题排查都有哪些手段?
答:
使用 show processlist 命令查看当前所有连接信息
使用 explain 命令查询 SQL 语句执行计划
开启慢查询日志,查看慢查询的 SQL
178.如何做 mysql 的性能优化?
答:
为搜索字段创建索引
避免使用 select *,列出需要查询的字段
垂直分割分表
选择正确的存储引擎
十八、Redis
重要链接:https://blog.csdn.net/u010963948/article/details/79589710
179.redis 是什么?都有哪些使用场景?
答:redis是一种开源的使用c语言编写的开源、支持网络,可基于内存亦可持久化的日志型的key-value数据库,并提供多种语言的api。可用于缓存,事件发布或订阅,排行榜,计数器,高速队列等多种场景。
或者:Redis 是一个基于内存的高性能key-value数据库。
使用场景分析:https://www.cnblogs.com/jasonZh/p/9513948.html
180.redis 有哪些功能?
答:
1.基于本机内存的缓存
2.服务器端的redis
3.持久化(Persistence)
4.哨兵(Sentinel)和复制(Replication)
5.集群(Cluster)
参考网址:https://www.cnblogs.com/linianhui/p/what-problem-does-redis-solve.html
181.redis 和 memecache 有什么区别?(考的几率小)
答:
1)、存储方式 Memecache把数据全部存在内存之中,断电后会挂掉,数据不能超过内存大小。 Redis有部份存在硬盘上,这样能保证数据的持久性。
2)、数据支持类型 Memcache对数据类型支持相对简单。 Redis有复杂的数据类型。
3)、使用底层模型不同 它们之间底层实现方式 以及与客户端之间通信的应用协议不一样。 Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求。
补充题目:redis相比memcached有哪些优势?
(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型
(2) redis的速度比memcached快很多 (3) redis可以持久化其数据
182.redis 为什么是单线程的?
答:redis利用队列技术将并发访问变为串行访问,消除了传统数据库串行控制的开销
183.什么是缓存穿透?怎么解决?
答:
缓存穿透是指查询一个一定不存在的数据,由于缓存是不命中时需要从数据库查询,查不到数据则不写入缓存,这将导致这个不存在的数据每次请求都要到数据库去查询,造成缓存穿透。
解决办法:
1布隆过滤
2. 缓存空对象. 将 null 变成一个值.
184.redis 支持的数据类型有哪些?
答:String(字符串),List(列表),Hsah(字典),Set(集合),ZSet(或者Sorted Set有序集合)
使用场景分析:https://www.cnblogs.com/jasonZh/p/9513948.html
185.redis 支持的 java 客户端都有哪些?(面试生僻题目,可不看)
答:https://blog.csdn.net/moonpure/article/details/82659460
https://blog.csdn.net/moonpure/article/details/86607022
186.jedis 和 redisson 有哪些区别?
答:见上一条链接
187.怎么保证缓存和数据库数据的一致性?(这个问题非常不常见)
答:https://yq.aliyun.com/articles/702068
188.redis 持久化有几种方式?
答:
1、RDB(日照)
该机制可以在指定的时间间隔内生成数据集的时间点快照。
2、AOF(日志文件)
记录服务器执行的所有操作命令,并在服务器启动时,通过重新执行这些命令来还原数据集。AOF文件中的命令全部以Redis协议的格式来保存。
3、虚拟内存方式(这个不记,仅作参考)
当你的key很小而value很大时,使用VM的效果会比较好.因为这样节约的内存比较大.
当你的key不小时,可以考虑使用一些非常方法将很大的key变成很大的value,比如你可以考虑将key,value组合成一个新的value.
vm-max-threads这个参数,可以设置访问swap文件的线程数,设置最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的.可能会造成比较长时间的延迟,但是对数据完整性有很好的保证.
自己测试的时候发现用虚拟内存性能也不错。如果数据量很大,可以考虑分布式或者其他数据库
189.redis 怎么实现分布式锁?
答案:
参考链接:https://www.cnblogs.com/cmyxn/p/9047848.html
https://blog.csdn.net/tuesdayma/article/details/82751790
https://blog.csdn.net/L_BestCoder/article/details/79336986
190.redis 分布式锁有什么缺陷?
答案:
参考链接:https://blog.csdn.net/qq_35666577/article/details/80431019
https://blog.csdn.net/m0_37587333/article/details/94378788
191.redis 如何做内存优化?
答:
1.尽量使用短的key
2.避免使用keys *
3.在存到Redis之前先把你的数据压缩下
4.设置key有效期
5.尽可能地使用hashes哈希存储
6.当业务场景不需要数据持久化时,关闭所有的持久化方式可以获得最佳的性
7.想要一次添加多条数据的时候可以使用管道
参考链接:https://www.cnblogs.com/moonandstar08/p/7282108.html
192.redis 淘汰策略有哪些?
答:
redis内存数据数据集大小升到一定大的时候,就会实行数据淘汰策略(回收策略)。
1,volatile-lru:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中用lru算法淘汰最近最少使用的数据
2,allkey-lru:从所有key的哈希表(server.db[i].dict)中随机挑选多个key,然后再选到的key中利用lru算法淘汰最近最少使用的数据
3,volatile-ttl:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选多个key,然后在选到的key中选择过期时间最小的数据淘汰掉。
4,volatile-random:从已设置过期时间的哈希表(server.db[i].expires)中随机挑选key淘汰掉。
5,allkey-random:从所有的key的哈希表(server.db[i].dict)中随机挑数据淘汰
6,no-eviction(驱逐):内存达到上限,不淘汰数据。
参考链接:https://blog.csdn.net/weixin_39590058/article/details/88648919
193.redis 常见的性能问题有哪些?该如何解决?
答:
链接:https://www.cnblogs.com/hello-/articles/9599300.html
链接:https://blog.csdn.net/jiangbb8686/article/details/86707613
十九、JVM
194.说一下 jvm 的主要组成部分?及其作用?
答:
类加载器(ClassLoader)
运行时数据区(Runtime Data Area)
执行引擎(Execution Engine)
本地库接口(Native Interface)
组件的作用: 首先通过类加载器(ClassLoader)会把 Java 代码转换成字节码,运行时数据区(Runtime Data Area)再把字节码加载到内存中,而字节码文件只是 JVM 的一套指令集规范,并不能直接交个底层操作系统去执行,因此需要特定的命令解析器执行引擎(Execution Engine),将字节码翻译成底层系统指令,再交由 CPU 去执行,而这个过程中需要调用其他语言的本地库接口(Native Interface)来实现整个程序的功能
195.说一下 jvm 运行时数据区?
答:
不同虚拟机的运行时数据区可能略微有所不同,但都会遵从 Java 虚拟机规范, Java 虚拟机规范规定的区域分为以下 5 个部分:
程序计数器(Program Counter Register):当前线程所执行的字节码的行号指示器,字节码解析器的工作是通过改变这个计数器的值,来选取下一条需要执行的字节码指令,分支、循环、跳转、异常处理、线程恢复等基础功能,都需要依赖这个计数器来完成
Java 虚拟机栈(Java Virtual Machine Stacks):用于存储局部变量表、操作数栈、动态链接、方法出口等信息
本地方法栈(Native Method Stack):与虚拟机栈的作用是一样的,只不过虚拟机栈是服务 Java 方法的,而本地方法栈是为虚拟机调用 Native 方法服务的
Java 堆(Java Heap):Java 虚拟机中内存最大的一块,是被所有线程共享的,几乎所有的对象实例都在这里分配内存
方法区(Methed Area):用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据
参考链接:https://www.cnblogs.com/zhouyuqin/p/5161677.html
https://blog.csdn.net/qq_39470733/article/details/80935743
196.说一下堆栈的区别?
答案一(个人推荐):
功能方面:堆是用来存放对象的,栈是用来执行程序的
共享性:堆是线程共享的,栈是线程私有的
空间大小:堆大小远远大于栈
答案二(作为补充参考):
堆和栈的区别:
【1】堆是由低地址向高地址扩展;栈是由高地址向低地址扩展
【2】堆中的内存需要手动申请和手动释放;栈中内存是由OS自动申请和自动释放,存放着参数、局部变量等内存
【3】堆中频繁调用malloc和free,会产生内存碎片,降低程序效率;而栈由于其先进后出的特性,不会产生内存碎片
【4】堆的分配效率较低,而栈的分配效率较高
(补充)栈的效率高的原因:
栈是操作系统提供的数据结构,计算机底层对栈提供了一系列支持:分配专门的寄存器存储栈的地址,压栈和入栈有专门的指令执行;而堆是由C/C++函数库提供的,机制复杂,需要一些列分配内存、合并内存和释放内存的算法,因此效率较低。
197.队列和栈是什么?有什么区别?
答:
队列和栈都是被用来预存储数据的。
队列允许先进先出检索元素,但也有例外的情况,Deque 接口允许从两端检索元素。
栈和队列很相似,但它运行对元素进行后进先出进行检索
补充:
JVM 中堆和栈属于不同的内存区域,使用目的也不同。栈常用于保存方法帧和局部变量,而对象总是在堆上分配。栈通常都比堆小,也不会在多个线程之间共享,而堆被整个 JVM 的所有线程共享。
198.什么是双亲委派模型?(几乎不考)
答:
在介绍双亲委派模型之前先说下类加载器。对于任意一个类,都需要由加载它的类加载器和这个类本身一同确立在 JVM 中的唯一性,每一个类加载器,都有一个独立的类名称空间。类加载器就是根据指定全限定名称将 class 文件加载到 JVM 内存,然后再转化为 class 对象。
类加载器分类:
启动类加载器(Bootstrap ClassLoader),是虚拟机自身的一部分,用来加载Java_HOME/lib/目录中的,或者被 -Xbootclasspath 参数所指定的路径中并且被虚拟机识别的类库
其他类加载器:
扩展类加载器(Extension ClassLoader):负责加载\lib\ext目录或Java. ext. dirs系统变量指定的路径中的所有类库
应用程序类加载器(Application ClassLoader)。负责加载用户类路径(classpath)上的指定类库,我们可以直接使用这个类加载器。一般情况,如果我们没有自定义类加载器默认就是用这个加载器
双亲委派模型:如果一个类加载器收到了类加载的请求,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,这样所有的加载请求都会被传送到顶层的启动类加载器中,只有当父加载无法完成加载请求(它的搜索范围中没找到所需的类)时,子加载器才会尝试去加载类
199.说一下类加载的执行过程?
答:
类装载分为以下 5 个步骤:
加载:根据查找路径找到相应的 class 文件然后导入
检查:检查加载的 class 文件的正确性
准备:给类中的静态变量分配内存空间
解析:虚拟机将常量池中的符号引用替换成直接引用的过程。符号引用就理解为一个标示,而在直接引用直接指向内存中的地址
初始化:对静态变量和静态代码块执行初始化工作
200.怎么判断对象是否可以被回收?
参考答案一:
一、引用计数算法:
判断对象的引用数量:
通过判断对象的引用数量来决定对象是否可以被回收;
每个对象实例都有一个引用计数器,被引用则+1,完成引用则-1;
任何引用计数为0的对象实例可以被当作垃圾收集;
优缺点:
优点:执行效率高,程序执行受影响较小;
缺点:无法检测出循环引用的情况,导致内存泄漏;
二、可达性分析算法:
通过判断对象的引用链是否可达来决定对象是否可以被回收;
可以作为GC Root的对象有:
虚拟机栈中引用的对象(栈帧中的本地变量表);
方法区中的常量引用对象;
方法区中类静态属性引用对象;
本地方法栈中JNI(Native方法)的引用对象;
活跃线程中的引用对象;
参考链接: https://www.cnblogs.com/hujinshui/p/10441230.html
https://blog.csdn.net/u012233285/article/details/61925319
参考答案二:
一般有两种方法来判断:
引用计数器:为每个对象创建一个引用计数,有对象引用时计数器 +1,引用被释放时计数 -1,当计数器为 0 时就可以被回收。它有一个缺点不能解决循环引用的问题
可达性分析:从 GC Roots 开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连时,则证明此对象是可以被回收的
201.java 中都有哪些引用类型?
答:
强引用:发生 gc 的时候不会被回收
软引用:有用但不是必须的对象,在发生内存溢出之前会被回收
弱引用:有用但不是必须的对象,在下一次GC时会被回收
虚引用(幽灵引用/幻影引用):无法通过虚引用获得对象,用 PhantomReference 实现虚引用,虚引用的用途是在 gc 时返回一个通知
202.说一下 jvm 有哪些垃圾回收算法?
答:
标记-清除算法:标记无用对象,然后进行清除回收。缺点:效率不高,无法清除垃圾碎片
标记-整理算法:标记无用对象,让所有存活的对象都向一端移动,然后直接清除掉端边界以外的内存
复制算法:按照容量划分二个大小相等的内存区域,当一块用完的时候将活着的对象复制到另一块上,然后再把已使用的内存空间一次清理掉。缺点:内存使用率不高,只有原来的一半
分代算法:根据对象存活周期的不同将内存划分为几块,一般是新生代和老年代,新生代基本采用复制算法,老年代采用标记整理算法
203.说一下 jvm 有哪些垃圾回收器?
答:
Serial:最早的单线程串行垃圾回收器
Serial Old:Serial 垃圾回收器的老年版本,同样也是单线程的,可以作为 CMS 垃圾回收器的备选预案
ParNew:是 Serial 的多线程版本
Parallel 和 ParNew 收集器类似是多线程的,但 Parallel 是吞吐量优先的收集器,可以牺牲等待时间换取系统的吞吐量
Parallel Old 是 Parallel 老生代版本,Parallel 使用的是复制的内存回收算法,Parallel Old 使用的是标记-整理的内存回收算法
CMS:一种以获得最短停顿时间为目标的收集器,非常适用 B/S 系统
G1:一种兼顾吞吐量和停顿时间的 GC 实现,是 JDK 9 以后的默认 GC 选项
204.详细介绍一下 CMS 垃圾回收器?(不常考)
答:CMS 是英文 Concurrent Mark-Sweep 的简称,是以牺牲吞吐量为代价来获得最短回收停顿时间的垃圾回收器。对于要求服务器响应速度的应用上,这种垃圾回收器非常适合。在启动 JVM 的参数加上“-XX:+UseConcMarkSweepGC”来指定使用 CMS 垃圾回收器
CMS 使用的是标记-清除的算法实现的,所以在 gc 的时候回产生大量的内存碎片,当剩余内存不能满足程序运行要求时,系统将会出现 Concurrent Mode Failure,临时 CMS 会采用 Serial Old 回收器进行垃圾清除,此时的性能将会被降低。
205.新生代垃圾回收器和老生代垃圾回收器都有哪些?有什么区别?
答:
新生代回收器:Serial、ParNew、Parallel Scavenge
老年代回收器:Serial Old、Parallel Old、CMS
整堆回收器:G1
新生代垃圾回收器一般采用的是复制算法,复制算法的优点是效率高,缺点是内存利用率低;老年代回收器一般采用的是标记-整理的算法进行垃圾回收
206.简述分代垃圾回收器是怎么工作的?
答:
分代回收器有两个分区:老生代和新生代,新生代默认的空间占比总空间的 1/3,老生代的默认占比是 2/3
新生代使用的是复制算法,新生代里有 3 个分区:Eden、To Survivor、From Survivor,它们的默认占比是 8:1:1,它的执行流程如下:
把 Eden + From Survivor 存活的对象放入 To Survivor 区
清空 Eden 和 From Survivor 分区
From Survivor 和 To Survivor 分区交换,From Survivor 变 To Survivor,To Survivor 变 From Survivor
每次在 From Survivor 到 To Survivor 移动时都存活的对象,年龄就 +1,当年龄到达 15(默认配置是 15)时,升级为老生代。大对象也会直接进入老生代。 老生代当空间占用到达某个值之后就会触发全局垃圾收回,一般使用标记整理的执行算法。以上这些循环往复就构成了整个分代垃圾回收的整体执行流程
207.说一下 jvm 调优的工具?
答:
JDK 自带了很多监控工具,都位于 JDK 的 bin 目录下,其中最常用的是 jconsole 和 jvisualvm 这两款视图监控工具
jconsole:用于对 JVM 中的内存、线程和类等进行监控;
jvisualvm:JDK 自带的全能分析工具,可以分析:内存快照、线程快照、程序死锁、监控内存的变化、gc 变化等
208.常用的 jvm 调优的参数都有哪些?
答:
-Xms2g:初始化推大小为 2g
-Xmx2g:堆最大内存为 2g
-XX:NewRatio=4:设置年轻的和老年代的内存比例为 1:4
-XX:SurvivorRatio=8:设置新生代 Eden 和 Survivor 比例为 8:2
–XX:+UseParNewGC:指定使用 ParNew + Serial Old 垃圾回收器组合
-XX:+UseParallelOldGC:指定使用 ParNew + ParNew Old 垃圾回收器组合
-XX:+UseConcMarkSweepGC:指定使用 CMS + Serial Old 垃圾回收器组合
-XX:+PrintGC:开启打印 gc 信息
-XX:+PrintGCDetails:打印 gc 详细信息
209.nginx的五种策略
答:
1、轮询(默认)
每个请求按时间顺序逐一分配到不同的后端服务器,如果后端服务器down掉,能自动剔除。
2、指定权重
指定轮询几率,weight和访问比率成正比,用于后端服务器性能不均的情况。
3、IP绑定 ip_hash
每个请求按访问ip的hash结果分配,这样每个访客固定访问一个后端服务器,可以解决session的问题。
4、fair(第三方)
按后端服务器的响应时间来分配请求,响应时间短的优先分配。
5、url_hash(第三方)
按访问url的hash结果来分配请求,使每个url定向到同一个后端服务器,后端服务器为缓存时比较有效。
详情:https://www.cnblogs.com/andashu/p/6377323.html
210.请解释Spring Bean的生命周期。★★★
答:
SpringBean的生命周期简单易懂,在一个Bean实例被初始化时,需要执行一系列的初始化操作,以达到可用状态。同样的,当一个Bean不在被调用时需要进行相关的解析操作,并从Bean容器中移除。
Spring Bean Factory负责管理在Spring容器中被创建的Bean的生命周期,Bean的生命周期由两组回调(Call back)方法组成。
初始化之后调用的回调方法和销毁之前调用的回调方法。
Spring框架提供了以下四种方式来管理Bean的生命周期:
InitializingBean和DisposableBean回调接口
针对特殊行为的其他Aware接口
Bean配置文件中的Custom init()方法和destroy()方法
@PostConstruct和@PreDestroy注解方式
//使用customInit()和 customDestroy()方法管理bean生命周期的代码样例如下
<beans>
<bean id="demoBean" class="com.howtodoinjava.task.DemoBean"
init-method="customInit" destroy-method="customDestroy"></bean>
</beans>
面试题
211.如果zookeeper宕机服务能否正常运行???
答:服务依然可以正常运行!!!!
212.如果zk宕机之后生产者宕机,问用户是否受限???
答案:
如果当前还有服务提供者,那么程序依然正常访问!!!
原因:
因为服务消费者启动时将注册中心中的服务列表数据缓存到本地.所以zk宕机时不受影响.
如果在zk宕机的同时生产者也宕机,则消费者在尝试调用生产者时发现服务器宕机.则在本地自动表示为down.之后的访问不会再次访问故障机.
但是现在程序运行处于高风险运行的状态.
213.COOKIE禁用怎么办???
答: 需要改变后台的传参方式.
1.解决策略一:URL重写技术. 每次用户请求都需要拼接?sessionId=100100
http://www.jt.com?sessionId=1231123
http://wwww.cart.com?sessionId=12312123
一般大型公司为了运行的稳定一般不会进行处理.另外用户禁用COOKIE的的人数较少.不能因为少部分人影响整个网站的运行.
2.解决策略二:实现SessionId的共享.利用Nginx实现.具体操作我找找资料
214.请简述一下css用法???
答:
(1)css是用来渲染HTML页面的,将页面元素与样式进行分离
(2)引入css文件:<link type="text/csss" rel="stylesheet" href="css文件路径">
(3)类型:标签选择器,类选择器,ID选择器
215.AJAX的原理???AJAX的优点,缺点??
答:
(1)原理(简单理解):Ajax通过XMLHttpRequest对象向服务器发送请求,从服务器获取数据,然后进行dom操作,其中XMLHttpRequest有俩个方法,一个是Open(),一个是Send();
(1.1)Open():它规定了向服务器提交数据的类型
它规定了向服务器请求的URL地址和参数,
传输方式:false是同步,true是异步传输
(1.2)send():用来发送请求的
(2)优点:
Ajax可以实现页面无刷新获取数据,用户体验良好
Ajax采用异步的方式请求数据,所以他请求数据的效率更高
Ajax可以减轻服务端的压力
(3)缺点:
Ajax对于回退按钮无法实现
Ajax由于将一些数据放在了客户端,所以安全性不高
Ajax不能很好的支持移动端
216.JAVA的反射机制???
答:
(1)JAVA的反射机制通俗点讲就是动态的获取自身的信息,通过类名来获取该类的全部信息
(2)动态编译:运行时确定对象类型,绑定对象,动态的发挥了JAVA的灵活性,体现了多态的应用,有降低耦合的功能
217.事务的特性:
答:ACID
原子性:一个事务不可再分割,要么都执行要么都不执行
一致性:一个事务执行会使数据从一个一致状态切换到另外一个一致状态
隔离性:一个事务的执行不受其他事务的干扰
持久性:一个事务一旦提交,则会永久的改变数据库的数据.
218.Java中X++与++x的区别
答:首先,两个操作都是自增操作,都只能对变量进行该操作,但是两种自增有些许区别++x 先将x的值自增1,然后再在当前表达式中使用x的值x++ 先在当前表达式中使用x的值,然后再将x的值自增1举例:
(1) int x=1;
System.out.println(x++);//输出1, x++先在当前表达式中使用x的值,然后再将x的值自增1
System.out.println(x); //输出2,经过上一条指令x自增了1
(2)int x=1;
System.out.println(++x); //输出2, ++x 先将x的值自增1,然后再在当前表达式中使用x的值
System.out.println(x); //输出2,经过上一条指令x自增了1
author:ShenYu,come from China