Java面试题汇总(最新版)

1、面向对象特征
抽象:将一些事物的共性抽离出来归为一个类。
封装:把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承:子类继承父类的特征和行为。子类可以有父类的方法,属性(非private)。子类也可以对父类进行扩展,也可以重写父类的方法。缺点就是提高代码之间的耦合性。
多态:同一类的对象调用相同方法可以表现出不同的行为。
多态分为编译时多态和运行时多态,编译时多态主要指方法的重载,运行时多态指程序中定义的对象引用所指向的具体类型在运行期间才确定。多态性允许一个接口被多个同类使用,弥补了单继承的不足。

2、类和对象的关系
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。

3、面向过程和面向对象的区别
(1)编程思路不同: 面向过程以实现功能的函数开发为主,而面向对象要首先抽象出类、属性及其方法,然后通过实例化类、执行方法来完成功能。
(2)封装性:都具有封装性,但是面向过程是封装的是功能,而面向对象封装的是数据和功能。
(3)面向对象具有继承性和多态性,而面向过程没有继承性和多态性,所以面向对象优势是明显。

4、什么是JVM?Java虚拟机包括什么?
Java虚拟机(Java Virtual Machine)是可以执行Java字节码的虚拟机,每个Java源文件将被编译成字节码文件,然后在JVM中执行。Java虚拟机包括寄存器,堆栈和处理器。

5、this和super关键字的作用
(1)this是对象内部指代自身的引用
this可以调用成员变量,通常用于解决成员变量和局部变量同名冲突;
this可以调用成员方法;
this可以在构造方法中调用重载的构造方法,且必须是构造方法的第一条语句。
(2)super代表对当前对象的直接父类对象的引用
super可以调用直接父类的成员变量(注意权限修饰符的影响,比如不能访问private成员);
super可以调用直接父类的成员方法(注意权限修饰符的影响,比如不能访问private成员);
super可以调用直接父类的构造方法,只限构造方法中使用,且必须是第一条语句。

6、 static变量和非static变量的区别
(1)在内存中份数不同:不管有多少个对象,static变量只有1份,对于每个对象,实例变量都会有单独的一份;static变量是属于整个类的,也称为类变量,而非静态变量是属于对象的,也称为实例变量;
(2)在内存中存放的位置不同:静态变量存在方法区中,实例变量存在堆内存中。
(3)static代码块,当类被第一次使用时(可能是调用static属性和方法,或者创建其对象)执行静态代码块,且只被执行一次,主要作用是实现static属性的初始化。

7、final和abstract关键字的作用
(1)abstract可以用来修饰类和方法,不能用来修饰属性和构造方法;使用abstract修饰的类是抽象类,需要被继承,使用abstract修饰的方法是抽象方法,需要子类被重写。
(2)final可以用来修饰类、方法和属性,不能修饰构造方法。使用final修饰的类不能被继承,使用final修饰的方法不能被重写,使用final修饰的变量的值不能被修改,所以就成了常量。
特别注意:final修饰基本类型变量,其值不能改变。但是final修饰引用类型变量,栈内存中的引用不能改变,但是所指向的堆内存中的对象的属性值仍旧可以改变。

8、重载和重写的区别
(1)override(重写)
方法名、参数、返回值相同。
子类方法不能缩小父类方法的访问权限。
子类方法不能抛出比父类方法更多的异常(但子类方法可以不抛出异常)。
存在于父类和子类之间。
方法被定义为final不能被重写。
方法重写实现的是运行时的多态性

(2)overload(重载)
参数类型、个数、顺序至少有一个不相同。
不能重载只有返回值不同的方法名。
存在于同类中。
方法重载实现的是编译时的多态性
注意:构造方法既能重写,也能重载;构造器(constructor)不能被继承,因此不能被重写,但可以被重载。

9、final、finally、finalize的区别
(1)final是定义类、⽅法、字段的修饰符,表示类不可被继承,⽅法不能被重写,字段值不能被修改。
(2)finally在异常处理时提供 finally 块来执行任何清除操作。如果有finally的话,则不管是否发生异常,finally语句都会被执行。
(3)finalize是Object的⼀个⽅法,在对象被虚拟机回收时会判断是否执⾏该⽅法,当对象没有覆盖finalize⽅法,或者finalize⽅法已经被虚拟机调⽤过,虚拟机将这两种情况都视为“没有必要执⾏”。

10、 普通类和抽象类的区别
a.普通类不能包含抽象方法,抽象类可以包含抽象方法;
b.普通类可以直接实例化,抽象类不能直接实例化。

11、抽象类和接口有什么区别
a.实现:抽象类的子类使用extends来继承;接口必须使用implement来实现接口;
b.构造函数:抽象类可以有构造函数,接口不能有;
c.main方法:抽象类可以有main方法,并且能运行它,接口不能有main方法;
d.实现数量:类可以实现多个接口,但类只能继承一个抽象类;
e.访问修饰符:接口中的方法默认使用public修饰,而抽象类中的方法可以是任意访问修饰符。
延伸:抽象类能使用 final 修饰吗?
不能,定义抽象类就是让其他类继承的,如果定义为 final 该类就不能被继承,这样彼此就会产生矛盾,所以 final 不能修饰抽象类。

12、==和equals的区别
(1)==是运算符,⽽equals是Object的基本⽅法,==⽤于基本类型的数据的⽐较,或者是⽐较两个对象的引⽤是否相同;
(2)equals⽤于⽐较两个对象的值是否相等,例如字符串的⽐较。

13、 String、StringBuffer、StringBuilder区别
(1)String类是不可变类,即一旦一个String对象被创建后,包含在这个对象中的字符序列是不可改变的,直至这个对象销毁。
(2)StringBuffer类则代表一个字符序列可变的字符串,可以通过append、insert、reverse、setChartAt、setLength等方法改变其内容。一旦生成了最终的字符串,调用toString方法将其转变为String。
(3)JDK1.5新增了一个StringBuilder类,与StringBuffer相似,构造方法和方法基本相同。不同是StringBuffer是线程安全的,而StringBuilder是线程不安全的,所以性能略高。通常情况下,创建一个内容可变的字符串,应该优先考虑使用StringBuilder。
延伸:(1)Java中操作字符串为 String、StringBuffer和StringBuilder
(2)如何将字符串反转?
使用StringBuffer或StringBuilder的reverse()方法

14、&和&&的区别
(1)&和&&都可以用作逻辑与的运算符,表示逻辑与(and),当运算符两边的表达式的结果都为true时,整个运算结果才为true,否则,只要有一方为false,则结果为false。
(2)&&还具有短路的功能,即如果第一个表达式为false,则不再计算第二个表达式。
(3)&还可以用作位运算符,当&操作符两边的表达式不是boolean类型时,&表示按位与操作,我们通常使用0x0f来与一个整数进行&运算,来获取该整数的最低4个bit位,例如,0x31 & 0x0f的结果为0x01。

15、Error和Exception的区别
(1)Error类,表示仅靠程序本身无法恢复的严重错误,比如说内存溢出、动态链接异常、虚拟机错误。应用程序不应该抛出这种类型的对象。
(2)Exception类,由Java应用程序抛出和处理的非严重错误,比如所需文件没有找到、零作除数,数组下标越界等。它的各种不同子类分别对应不同类型异常。可分为两类:Checked异常和Runtime异常。

16、 Checked异常和Runtime异常的区别
(1)运行时异常:包括RuntimeaException及其所有子类,不要求程序必须对它们作出处理;即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。
(2)Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理。

17、多态的技能点(前提条件,向上转型、向下转型)
(1)多态条件:1.有继承 2. 有重写 3. 要有⽗类引⽤指向⼦类对象;如Animal a = new Tiger();
(2)向上转型:将一个父类的引用指向一个子类对象,成为向上转型,自动进行类型转换。
(3)向下转型:将一个指向子类对象的引用赋给一个子类的引用,成为向下转型,此时必须进行强制类型转换。向下转型时可以结合使用instanceof运算符进行强制类型转换,比如出现转换异常。

18、异常处理中throw和throws的区别
(1)作用不同:throw用于程序自行产生并抛出异常;throws用于声明在该方法内抛出了异常。
(2)使用的位置不同:throw位于方法体内部,可以作为单独语句使用;throws必须跟在方法参数列表的后面,不能单独使用。
(3)内容不同:throw抛出一个异常对象,且只能是一个;throws后面跟异常类,而且可以有多个。

19、 Java异常处理try-catch-finally的执行过程
程序首先执行可能发生异常的try语句块。如果try语句没有出现异常则执行完后跳至finally语句块执行;如果try语句出现异常,则中断执行并根据发生的异常类型跳至相应的catch语句块执行处理。catch语句块可以有多个,分别捕获不同类型的异常。catch语句块执行完后程序会继续执行finally语句块。finally语句是可选的,如果有的话,则不管是否发生异常,finally语句都会被执行。

20、Integer与int的区别
Integer是java为int提供的包装类,int的默认值为0,而Integer的默认值为null。

21、 Collection和Collections的区别
(1)Collection是Java提供的集合接口,存储一组不唯一,无序的对象。它有两个子接口List和Set。
(2)Collections是个工具类,专门用来操作集合类 ,它提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

22、http 请求的get和post的区别
a.Get是不安全的,因为在传输过程,数据被放在请求的URL中;Post的所有操作对用户来说都是不可见的。
b.Get传送的数据量较小,这主要是因为受URL长度限制;Post传送的数据量较大,一般被默认为不受限制。
c.Get限制Form表单的数据集的值必须为ASCII字符;而Post支持整个ISO10646字符集。
d.Get执行效率却比Post方法好。Get是form提交的默认方法。

23、重定向(redirect)和请求(forward)转发区别
a.请求转发只能将请求转发给同一个Web应用中的其他资源,而重定向不仅可以定向到当前应用程序中的其他资源,也可以重定向到其他站点上的资源;
b.重定向结束后,浏览器显示的url会发生改变,由初始的url地址变成重定向的目标url地址,而请求转发结束后,浏览器显示的url地址不变;
c.转发是一次请求,重定向是二次请求;
d.转发是在服务器进行的,重定向在客户端进行。
e.数据共享:转发 可以共享 request 里的数据,重定向 不能共享;
f.效率:转发 比 重定向 效率高。
延伸:http 响应码 301 和 302 代表的是什么?
301:永久重定向;302:暂时重定向。

24、进程和线程的关系和区别?
(1)定义:
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的一个独立单位。
线程是进程的一个实体,是CPU调度和分派的基本单位,他是比进程更小的能独立运行的基本单位,线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),一个线程可以创建和撤销另一个线程。
(2)进程和线程的关系:
1> 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
2> 资源分配给进程,同一进程的所有线程共享该进程的所有资源。
3> 线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步。
4> 处理机分给线程,即真正在处理机上运行的是线程。
5> 线程是指进程内的一个执行单元,也是进程内的可调度实体。
(3)线程与进程的区别:
1> 调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。
2> 并发性:不同进程之间可以并发执行,同一个进程的多个线程之间也可以并发执行。
3> 拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源。
4> 系统开销:在创建或撤销进程的时候,由于系统都要为之分配和回收资源,导致系统的明显大于创建或撤销线程时的开销。但进程有独立的地址空间,进程崩溃后,在保护模式下不会对其他的进程产生影响,而线程只是一个进程中的不同的执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但是在进程切换时,耗费的资源较大,效率要差些。

25、List、Set、Map以及Array的区别
Array:数组,可以存储对象和基本数据类型,长度固定。
Collection:集合(单列),用于存储对象、不能存储基本数据类型(int,char等),但可以存储基本数据类型包装类(int-Integer,char-Character等),长度可变。

Array与ArrayList类的区别:
Arrays可以包含基础数据类型或者对象,而ArrayList只能包含对象。
Arrays有固定长度,而ArrayList长度则是动态的。

集合和数组的区别
a.数据时固定长度的,集合长度是可变的
b.数组可以存储基本数据类型,也可以存储引用数据类型,而集合只能存储引用数据类型
c.数组存储的元素必须是同一数据类型,而集合存储的对象可以是不同数据类型。

List
特征:元素有序,可重复。
ArrayList:数组。特点:有索引(脚标),所以查找快,增删后每个元素的索引都发生改变,所以增删慢,而且数组越长增删越慢。
LinkedList:链表。特点:无索引,每个元素都包含下一元素地址,查找需要逐一进行,所以查找慢,但是增删快只需要改变元素后面的地址。

ArrayList和LinkedList区别:
(1)ArrayList是基于索引的数据结构,底层由Array支持实现。它提供了以时间复杂度为O(1)的性能随机访问它的元素,另一方面,LinkedList以元素列表的方式来存储它的数据,每一个元素与它前一个和后一个元素都是相连的。对元素查询操作的时间复杂度为O(n)。
(2)对元素的插入、添加、移除操作,与ArrayList相比,LinkedList更快,因为,当一个元素被添加到集合内部的任意位置时,LinkedList不需要重新调整数组大小或者更新索引。
(3)LinkedList比ArrayList消耗更多的内存,因为LinkedList中每一个节点都存储了两个引用,一个是它前一个元素,一个是它后一个元素。

如何实现数组和 List 之间的转换?
数组转 List:使用 Arrays. asList(array) 进行转换。
List 转数组:使用 List 自带的 toArray() 方法。

Array 和 ArrayList 有何区别?
Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。

Set
特征:元素无序,不重复,无索引。
HashSet:哈希表。特点:线程非同步,保证元素唯一性,它不保证 set 元素的迭代顺序。
TreeSet:二叉树。特点:可对用两种方法对集合中元素排序,1.实现comparable接口,覆盖compareTo方法。2.集合建立时规定,并自定义比较类。

Map
特征:双列集合,用于存放键值对。键值是唯一的,不可重复。
Hashtable:内部存储的键值对是无序的是按照哈希算法进行排序,与 HashMap 最大的区别就是线程安全。键或者值不能为 null,为 null 就会抛出空指针异常。
TreeMap:基于红黑树 (red-black tree) 数据结构实现,按 key 排序,默认的排序方式是升序。
LinkedHashMap:有序的 Map 集合实现类,相当于一个栈,先进后出。

HashMap工作原理
Java 中的 HashMap 是用来存储键值对的。 HashMap 需要一个 hash 函数,它使用 hashCode 和 equals 方法,来进行 collection 中元素的保存和查找。调用 put 方法时,HashMap 会计算键(key)的 hash 值,然后将键值对存到 collection 的适当索引下。如果键已经存在,那么相应的值会更新。HashMap 的重要特征主要有它的容量,装载因子(load factor)和容量扩充(threshold resizing)。
在这里插入图片描述
26、String 类常用方法
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。

27、什么是 Java 序列化?什么情况下需要序列化?
Java 序列化是为了保存各种对象在内存中的状态,并且可以把保存的对象状态再读出来。
a.想把内存中的对象状态保存到一个文件中或者数据库中时候;
b.想用套接字在网络上传送对象的时候;
c.想通过RMI(远程方法调用)传输对象的时候。

28、线程的生命周期
线程是一个动态执行的过程,它是一个从产生到死亡的过程。
线程的五个状态(创建,就绪,运行,阻塞和死亡)
a.创建状态:生成线程对象,并没有调用该对象的start方法,这是线程处于创建状态
b.就绪状态:当调用了线程对象的start方法之后,该线程就进入了就绪状态
c.运行状态:线程调度程序将处于就绪状态的线程设置为当前线程,此时线程就进入了运行状态,开始运行run函数当中的代码
d.阻塞状态:线程正在运行的时候,被暂停,通常是为了等待某个时间的发生(比如说某项资源就绪)之后再继续运行。sleep,suspend,wait等方法都可以导致线程阻塞。
e.死亡状态:如果一个线程的run方法执行结束或者调用stop方法后,该线程就会死亡。对于已经死亡的线程,无法再使用start方法令其进入就绪状态。

29、为什么引入事务?事务的基本特性
(1)事务是由一步或者几步数据库操作序列组成的逻辑执行单元,这系列操作要么全部执行,要么全部放弃执行。
(2)事务具有四个特性。原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持续性(Durability),简称为ACID。
(3)数据库事务有一列语句组成:一组DML语句、一个DDL语句、一个DCL语句。
(4)JDBC默认开启事务。每条SQL语句一旦执行就会立即提交到数据库。如果希望多条SQL语句为一个事务,需要关闭事务的自动提交。并且手动提交或回滚。事务操作语句有:Conn.setAutoCommit(false); conn.commit(); conn.rollback();
(5)Hibernate默认关闭事务的自动提交。必须手动开启事务和提交/回滚事务。

30、TCP协议和UDP协议的区别?
(1)TCP是面向连接的传输。UDP是无连接的传输;
(2)TCP有流量控制、拥塞控制,检验数据数据按序到达,而UDP则相反;
(3)TCP的路由选择只发生在建立连接的时候,而UDP的每个报文都要进行路由选择;
(4)TCP是可靠性传输,他的可靠性是由超时重发机制实现的,而UDP则是不可靠传输;
(5)因为UDP少了很多控制信息,所以传输速度比TCP速度快;
(6)TCP适合用于传输大量数据,UDP适合用于传输小量数据。

31、过滤器和拦截器的区别:
  ①拦截器是基于java的反射机制的,而过滤器是基于函数回调。
  ②拦截器不依赖与servlet容器,过滤器依赖与servlet容器。
  ③拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
  ④拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
  ⑤在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
  ⑥拦截器可以获取IOC容器中的各个bean,而过滤器就不行,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
  
32、HashSet和HashMap的区别

HashMap HashSet
HashMap实现了Map接口 HashSet实现了Set接口
HashMap储存键值对 HashSet仅仅存储对象
使用put()方法将元素放入map中 使用add()方法将元素放入set中
HashMap中使用键对象来计算hashcode值 HashSet使用成员对象来计算hashcode值,对于两个对象来说hashcode可能相同,所以equals()方法用来判断对象的相等性,如果两个对象不同的话,那么返回false
HashMap比较快,因为是使用唯一的键来获取对象 HashSet较HashMap来说比较慢

33、HashMap和Hashtable的区别
(1)Hashtable 是不允许键或值为 null 的,HashMap 的键值则都可以为 null。
(2)添加key-value的hash值算法不同:HashMap添加元素时,是使用自定义的哈希算法,而HashTable是直接采用key的hashCode()
(3)实现方式不同:Hashtable 继承的是 Dictionary类,而 HashMap 继承的是 AbstractMap 类。
(4)初始化容量不同:HashMap 的初始容量为:16,Hashtable 初始容量为:11,两者的负载因子默认都是:0.75。
(5)扩容机制不同:当已用容量>总容量 * 负载因子时,HashMap 扩容规则为当前容量翻倍,Hashtable 扩容规则为当前容量翻倍 +1。
(6)支持的遍历种类不同:HashMap只支持Iterator遍历,而HashTable支持Iterator和Enumeration两种方式遍历。
(7)部分API不同:HashMap不支持contains(Object value)方法,没有重写toString()方法,而HashTable支持contains(Object value)方法,而且重写了toString()方法
(8)迭代器不同:HashMap的迭代器(Iterator)是fail-fast迭代器,而Hashtable的enumerator迭代器不是fail-fast的。所以当有其它线程改变了HashMap的结构(增加或者移除元素),将会抛出ConcurrentModificationException,但迭代器本身的remove()方法移除元素则不会抛出ConcurrentModificationException异常。但这并不是一个一定发生的行为,要看JVM。而Hashtable 则不会。
(9)线程安全性,HashMap是非synchronized的,而Hashtable是synchronized的。这说明Hashtable是线程安全的,而且多个线程可以共享一个Hashtable;而HashMap如果没有正确的同步的话,是不能被多个线程所共享的。但是,Java 5中为我们提供了ConcurrentHashMap,它是Hashtable的替代,而且比Hashtable的扩展性更好。
(10)同步和速度,由于Hashtable是线程安全的,也是synchronized的,所以在单线程环境下比HashMap要慢。如果你不需要同步且只需要单一线程的话,那么使用HashMap性能要比Hashtable好一些。此时,HashMap是个不错的选择。

34、ArrayList与Vector区别
(1)Vector比ArrayList先存在。Vector是同步的,Vector的对象是线程安全的;ArrayList是异步的,ArrayList的对象不是线程安全的。同步影响执行效率,所以ArrayList比Vector性能好。
(2)ArrayList和Vector都有一个初始的容量大小,当存储的空间不够时,需要增加存储空间,Vector默认增长原来的一倍,而ArrayList是原来的0.5倍。ArrayList与Vector都可以设置初始的空间大小,Vector还可以设置增长的空间大小。

35、如何实现线程同步?
线程同步的实现方案:同步代码块和同步方法,均需要使用synchronized关键字。

同步块和同步方法,哪个更好?
同步块,因为它不会锁住整个对象,而同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁。

36、GC
垃圾回收可以有效的防⽌内存泄漏,有效的使⽤可以使⽤的内存。垃圾回收器通常是作为⼀个单独的低优先级的线程运⾏,不可预知的情况下对内存堆中已经死亡的或者⻓时间没有使⽤的对象进⾏清除和回收,程序员不能实时的调⽤垃圾回收器对某个对象或所有对象进⾏垃圾回收。垃圾回收机制有分代复制垃圾回收、标记垃圾回收、增量垃圾回收等⽅式。

37、用最有效率的方法算出2乘以8等于多少?
使用位运算来实现效率最高,2乘以8相当于二进制位左移三位。所以实现方式为2<<3;因为将一个数左移n位,就相当于乘以了2的n次方,那么,一个数乘以8只要将其左移3位即可,而位运算cpu直接支持的,效率最高,所以,2乘以8等於几的最效率的方法是2 << 3。

38、 String s = new String(“abc”)创建了⼏个String Object?1个或2个对象,会创建String对象在常量池和堆中。
(1)String中的intern(),⾸先检查String pool是否有对应的字符串对象,如果有则返回,如果没有则在String pool中⽣成字符串,并返回地址。
(2)String中字⾯值”ab"之间拼接是在String pool中产⽣,⽽字⾯值与变量拼接字符串或者new String(“")则是在堆中产⽣对象。

39、内存溢出是怎么回事?
内存溢出 out of memory,是指程序在申请内存时,没有⾜够的内存空间供其使⽤,出现out of memory。
内存溢出可能的原因:
(1)程序中存在死循环
(2)静态变量和静态⽅法太多了
(3)内存泄漏:⽐如说⼀个静态的list,⼀直往⾥放值,⼜因为静态变量不会被释放,所以迟早是要内存溢出的
(4)大对象过多:java中的⼤对象是直接进⼊⽼年代的,然后当多个⼤对象同时⼯作时造成程序的可⽤内存⾮常⼩,⽐如我
list中原本最多可以放1000个对象,因为可⽤内存太⼩,放了500个就放不下了。
(5)程序分配内存过⼩:还有⼀种很常⻅的情况,在把⼀个很⼤的程序直接导⼊,直接就内存溢出了,原因就是内存相对这个程序就是太⼩了,需要⼿动增加内存。
内存泄漏 memory leak,是指程序在申请内存后,⽆法释放已申请的内存空间,⼀次内存泄漏危害可以忽略,但内存泄漏堆积后果很严重,⽆论多少内存,迟早会被占光。

40、幂等的处理⽅式:
接口可重复调⽤,在调⽤⽅多次调⽤的情况下,接口最终得到的结果是⼀致的。
(1)查询操作是天然幂等;
(2)唯⼀索引,防⽌新增脏数据;
(3)token机制,防⽌⻚⾯重复提交。

41、Servlet的生命周期
(1)加载Servlet:在下列时刻加载 Servlet:①如果已配置自动加载选项,则在启动服务器时自动加载 (web.xml中设置);②在服务器启动后,客户机首次向 Servlet 发出请求时;③重新加载 Servlet 时(只执行一次);
(2)实例化:加载 Servlet 后,服务器创建一个 Servlet 实例。(只执行一次);
(3)初始化:调用 Servlet 的 init() 方法。在初始化阶段,Servlet 初始化参数被传递给 Servlet 配置对象ServletConfig。 (只执行一次);
(4)请求处理:对于到达服务器的客户机请求,服务器创建针对此次请求的一个“请求”对象和一个“响应”对象。服务器调用 Servlet 的 service() 方法,该方法用于传递“请求”和“响应”对象。service() 方法从“请求”对象获得请求信息、处理该请求并用“响应”对象的方法以将响应传回客户机。service() 方法可以调用其它方法来处理请求,例如 doGet()、doPost() 或其它的方法。(每次请求都执行该步骤);
(5)销毁:当服务器不再需要 Servlet, 或重新装入 Servlet 的新实例时,服务器会调用 Servlet 的 destroy() 方法。(只执行一次)。

42、session和cookie的区别
(1)cookie数据存放在客户的浏览器上,session数据放在服务器上(sessionid可以通过cookie保存在客户端,也可以使用URL重写方式)。
(2)cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗,考虑到安全应当使用session
(3)session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
(4)单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的cookie不能超过3K。
(5)存储的多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie 只能存储在浏览器中。
个人建议:将登陆信息等重要信息存放为session;其他信息如需保留,可放在cookie。

session 的工作原理
客户端登录完成之后,服务器会创建对应的 session,session 创建完之后,会把 session 的 id 发送给客户端,客户端再存储到浏览器中。这样客户端每次访问服务器时,都会带着 sessionid,服务器拿到 sessionid 之后,在内存找到与之对应的 session,这样就可以正常工作了。

43、JSP的9个内置对象及其含义
(1)request表示HttpServletRequest对象。它包含了有关浏览器请求的信息。
(2)response表示HttpServletResponse对象,并提供了几个用于设置浏览器的响应的方法。
(3)out对象是javax.jsp.JspWriter的一个实例,并提供了几个方法使你能用于向浏览器回送输出结果。
(4)pageContext表示一个javax.servlet.jsp.PageContext对象。是用于方便存取各种范围的名字空间。
(5)session表示一个请求的javax.servlet.http.HttpSession对象。Session可以存贮用户的状态信息 。
(6)applicaton 表示一个javax.servle.ServletContext对象。这有助于查找有关servlet引擎和servlet环境的信息 。
(7)config表示一个javax.servlet.ServletConfig对象。该对象用于存取servlet实例的初始化参数。
(8)page表示从该页面产生的一个servlet实例。
(9)exception:exception对象用来处理错误异;如果使用exception,则必须指定page中的isErrorPage为true。
延伸:JSP 和 servlet 有什么区别?
JSP 是 servlet 技术的扩展,本质上就是 servlet 的简易方式。servlet 和 JSP 最主要的不同点在于,servlet 的应用逻辑是在 Java 文件中,并且完全从表示层中的 html 里分离开来,而 JSP 的情况是 Java 和 html 可以组合成一个扩展名为 JSP 的文件。JSP 侧重于视图,servlet 主要用于控制逻辑。

44、page/request/session/application作用域区别
page:当前页面范围
request:当前页面范围+转发页面(forward)+包含页面(include)
session:当前会话:session在以下几种情况下失效
(1)销毁session:Session.invalidate();
(2)超过最大非活动间隔时间;
(3)手动关闭浏览器(session并没有立刻失效,因为服务器端session仍旧存在,超过最大非活动间隔时间后真正失效);
application:当前应用;服务器重新启动前一直有效。

45、线程池
创建线程需要花费时间,如果任务来了才创建线程,那么响应时间会变长,为了避免这个问题,在程序启动的时候创建若干个线程来响应处理,需要的时候从池中获取线程不用自行创建,使用完毕不需要销毁线程而是放回池中,从而减少创建和销毁线程对象的开销,他们被称为线程池,线程叫工作线程。
Java通过Executors提供四种线程池,分别为:
a.newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
b.newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
c.newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
d.newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
线程池优点
a.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务
b.可以根据系统的承受能力,调整线程池中工作线程的数目,防止因为消耗过多的内存,而把服务器累趴下
c.减少在创建和销毁线程上所花的时间以及系统资源的开销
d.如果不使用线程池,有可能造成系统创建大量线程而导致消耗完系统内存

46、Java中有几种类型的流?
字节流和字符流。字节流继承于InputStream、OutputStream,字符流继承于Reader、Writer。在java.io 包中还有许多其他的流,主要是为了提高性能和使用方便。
关于Java的I/O需要注意的有两点:一是两种对称性(输入和输出的对称性,字节和字符的对称性);二是两种设计模式(适配器模式和装潢模式)。

47、请使用递归算法计算n!

public class Test {
    
    
	public int factorial(int n) {
    
    		
		if (n == 1 || n == 0){
    
    
			return n;
		}else{
    
    
			return n * factorial(n - 1);
		}			
	}
	public static void main(String[] args) {
    
    
		Test test = new Test();
		System.out.println(test.factorial(6));
	}
}

48、写出单例模式的示例代码

  • 饿汉式的单例模式
  • 在类加载的时候创建单例实例,而不是等到第一次请求实例的时候的时候创建
  • 1、私有的无参数构造方法Singleton(),避免外部创建实例
  • 2、私有静态属性instance
  • 3、公有静态方法getInstance()
public class Singleton {
    
    
	private static Singleton instance = new Singleton();	
	private Singleton(){
    
    	}
	public static Singleton getInstance(){
    
    	
		return instance;
	}
}

懒汉式的单例模式

  • 在类加载的时候不创建单例实例,只有在第一次请求实例的时候的时候创建
public class Singleton {
    
    	
	private static Singleton instance;	
	private Singleton(){
    
    	}
	/**
	 * 多线程情况的单例模式,避免创建多个对象
	*/
	public static Singleton getInstance(){
    
    
		if(instance ==null){
    
    //避免每次加锁,只有第一次没有创建对象时才加锁
			synchronized(Singleton.class){
    
    //加锁,只允许一个线程进入
				if(instance==null){
    
     //只创建一次对象
					instance = new Singleton();
				}			
			}
		}
		return instance;
	}
}

猜你喜欢

转载自blog.csdn.net/weixin_44495678/article/details/109477583