2020找工作期间自己总结的常见java基础面试题

2020.11.10:

2020.11.09:


spring boot:

提供了一种快速使用spring的方式,而不是功能上的增强,基于约定优于配置的思想,可以让开发人员不必在配置与逻辑业务之间进行思维的切换,
功能:自动配置,起步依赖,嵌入式服务,提供了两种配置文件类型。


SQL:结构化查询语言

  • 定义了操作所有关系型数据库的规则。但是每种数据库之间存在的不一样的地方称为方言。

  • 通用语法
    – 可单行,也可多行书写,以分号结尾;
    – 可使用空格和缩进来增强语句的可读性;
    –MySQL数据库的SQL语句不区分大小写,关键字建议使用大写。
    – 三种注释:
    ----> 单行:-- 注释内容,或者# 注释内容;
    ----> 多行注释:/* 注释内容 */

  • SQL的分类:DDL(数据定义语言,操作数据库,表,列),DML(数据操作语言,增删改表中的数据insert,delete,update),DQL(数据查询语言,用于查询数据库中表的记录。),DCL(数据控制语言,用来定义数据库的访问权限和安全级别及创建用户,关键字GRANT,REVOKE)


DQL语法:

select 字段列表…
from 表名…
where 跟表各列或多表之间应符合条件(<,>,=,in,like(_单个任意,%多个任意字符)),其后不可以跟聚合函数,因为聚合函数计算后,会在原表的基础上新增列。
group by 分组字段(列),分组之后只能查询分组字段和聚合函数。
having 分组后的条件,筛选。其后可以跟聚合函数的判断(count,avg,max,min,sum…)
order by 排序字段+ASC(默认升序)/ DESC(降序),…
limit 开始索引,每页查询条数
(分页限定,按order by 排序结果再分页)。


嵌套查询中的子查询

  • 子查询结果作为一个值,<,>,=…
  • 子查询结果作为一个单列集合,in(集合)…
  • 子查询结果多行多列,可作为一个虚拟表…

数据库建表的三大范式:

  • 第一范式:每列不可再拆分–原子性;
  • 第一范式满足后再谈第二范式:每个表只描述一件事情(一个客体的各属性),其他列均依赖于主键。
  • 第一、二范式满足后再谈第三范式:同意一表中不产生传递依赖,各列直接与主键相关,不能间接相关。

数据库事务的三大特征:

  • 原子性:同时成功或失败,无其它可能性。
  • 持久性:事务提交或者回滚后,数据库持久化地保存数据;
  • 隔离性: 多个事务之间相互独立;‘
  • 一致性:实务操作前后,数据总量保持不变。
    ####### MYSQL一条DML语句会自动提交一次事务。

隔离级别

多个事务操作同一批数据,会引发一些问题:
  • 脏读:读到另一个事务未提交的数据;
  • 不可重复读:同一个事务中多次读取到的数据不一致。
  • 幻读: 指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行
需设置不同的隔离级别
  • 读未提交:会引发脏读、不可重复读、幻读
  • 读已提交:只会解决脏读问题;
  • 可重复读:即可解决脏读,也解决了不可重复读问题;
  • 串行化:可解决所有的问题。
    !!!隔离级别从小到大,安全性越来越高,但是效率越来越低。

数组和List之间的转换?

  • array==>List :使用Arrays.asList(array);
  • List==>array:使用List自带的toArray()方法。

array与arrayList的区别?

  • arrayList只能存储对象,arraylist大小自动拓展,内置方法较多,如:addAll(),removeAll(), iterator();
  • array可以存基本数据类型和对象类型,指定固定大小,

什么是反射?

将类的各个组成部分封装成其他对象(Fields[ ] ,Construcior<>[ ],Method[ ]),再运行状态中,动态地获取类的所有属性和方法,对任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取类的信息,以及动态地调用对象的方法的功能,称为Java语言的反射机制。
好处:可以再程序运行过程中,操作这些对象,可以解耦提高程序的可拓展性。是框架设计的灵魂。


一、接口和抽象类的区别?

①、抽象类是对类的抽象,包括属性和行为;而接口是对行为的抽象。
②、抽象类中可以没有抽象方法,接口中必须有抽象方法。

③、接口中没有构造方法,Java 8 之前接口中成员只能是常量(public static final )和抽象方法(public abstract修饰),Java 8 接口中新增了默认方法(public default修饰,public修饰符可省略)和静态方法(public static修饰,public修饰符可省略。只能被接口调用,有方法体,)以及java 9 中新增的私有方法(private static 或者 private修饰,也即私有的静态方法和非静态的私有方法)。

补充:
接口中默认方法、静态方法、私有方法都有方法体。
不要求实现类重写default 修饰的默认方法:

1、如果重写,则需去掉default关键字。
2、如果不重写,实现类可以直接使用接口 中的默认方法。
默认方法可以调用私有的静态方法和非静态方法。而静态方法只能调用私有的静态方法

二、数组Array和列表ArrayList的区别?

Array可以包含基本类型和对象类型,Arraylist 只能包含对象类型,Array大小是固定的,Arraylist的大小是动态变化的。
ArrayList提供了更多的方法和特性,比如addAll()、removeAll()、iterator()等,对于基本类型数据,集合使用自动装箱来减少编码工作量,但是,当处理固定大小的基本数据类型的时候这种方式相对较慢。

三、静态变量 和 实例变量有什么区别?

  1. 在语法定义上的区别:静态变量前要加static关键字,而实例量前不加。
  2. 在程序运行时的区别
    实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。
    静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码文件,不用创建任何实例象,静态变量就会被分配空间,静态变量就可以被使用了。
总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。

四、类、以及类中变量和方法的加载顺序(参考加载机制)

什么时候类加载 ?

第一次需要使用类信息时加载。

类加载的原则:延迟加载,能不加载就不加载。

触发类加载的几种情况:

(1)、调用静态成员时,会加载静态成员真正所在的类及其父类。

通过子类调用父类的静态成员时,只会加载父类而不会加载子类。

(2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。

(3)、加载子类会先加载父类。(覆盖父类方法时所抛出的异常不能超过父类定义的范围)

注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。

例:public static final int a =123;

但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。

例:public static final int a = math.PI

如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载;

如果编译时不能确定其值的话,则运行时加载

类加载的顺序:

1.加载静态成员/代码块:

先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。

同一个类里的静态成员/代码块,按写代码的顺序加载。

如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。

调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。

***2.加载非静态成员/代码块:***(实例块在创建对象时才会被加载。而静态成员在不创建对象时可以加载)

先递归地加载父类的非静态成员/代码块(Object的最先);再依次加载到本类的非静态成员。

同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。

但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null 或者 0)。

调用父类的非静态成员(private 除外),也可以像调用自己的一样。

3.调用构造方法:

先递归地调用父类的构造方法(Object的最先)也就是上溯下行;默认调用父类空参的,也可在第一行写明调用父类某个带参的。

再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。

注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。

其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。

假设子类override父类的所有成员,包括静态成员、非静态属性和非静态方法。

由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;

由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。

java程序在执行过程中,类,对象以及它们成员加载、初始化的顺序如下:
1、首先加载要创建对象的类及其直接与间接父类。
2、在类被加载的同时会将静态成员进行加载,主要包括静态成员变量的初始化,静态语句块的执行,在加载时按代码的先后顺序进行。
3、需要的类加载完成后,开始创建对象,首先会加载非静态的成员,主要包括非静态成员变量的初始化,非静态语句块的执行,在加载时按代码的先后顺序进行。
4、最后执行构造器,构造器执行完毕,对象生成。

也就是说,只有当所有的类成员初始化完之后,才会调用类的构造函数创建对象。

顺序!!!:父类静态变量,父类静态代码块,子类静态变量,子类静态代码块,父类非静态变量,父类非静态代码块,父类构造函数,子类非静态变量,子类非静态代码块,子类构造函数。

一、类加载做了哪些事?
  之前没有进行类加载
 1.类加载,同时初始化类中静态的属性(赋默认值)
 2.执行静态代码块
 3.分配内存空间,同时初始化非静态的属性(赋默认值)
 4.如果声明属性的同时有显示的赋值,那么进行显示赋值把默认值覆盖
 5.执行匿名代码块
 6.执行构造器  
 7.返回内存地址

二、类加载的顺序
 1.static 变量
 2.static 代码块
 3.成员变量
 4.匿名块
 5.构造器
 ps:先加载父类,再加载子类;

如果类还没有被加载:
1、先执行父类的静态代码块和静态变量初始化,并且静态代码块和静态变量的执行顺序只跟代码中出现的顺序有关。
2、执行子类的静态代码块和静态变量初始化。
3、执行父类的实例变量初始化
4、执行父类的构造函数
5、执行子类的实例变量初始化
6、执行子类的构造函数

如果类已经被加载:
则静态代码块和静态变量就不用重复执行,再创建类对象时,只执行与实例相关的变量初始化和构造方法。


五、是否可以从一个static方法内部发出对非static方法的调用?

不可以。因为非static方法要与对象关联在一起,必须创建一个对象后,才可以在该对象上进行方法的调用,而static方法调用时不需要创建对象,可以直接调用。也就是说,一个static方法被调用时,可能还没有创建任何实例对象,所以,一个static方法内部不可以发出对非static方法的调用。


六、Integer与int的区别?

int是java提供的8种基本数据类型之一。Java为每个原始类型提供了封装类,Integer是Java为int提供的包装类。int的默认值是0,而Integer的默认值是null,即Integer可以区分出来未赋值和值为0的区别,int则无法表达出来未赋值的情况,例如想要表达出没有参加考试和考试成绩为0的区别,则只能用Integer。


七、Math.round(11.5)等于多少?Math.round(-11.5)等于多少?

Math类中提供了三种与取整有关的方法:ceil、floor、round。这些方法的作用与他们的英文名称的含义相对应,ceil的英文意思是装天花板,该方法就表示向上取整。floor的英文意思是地板,该方法就表示向下取整。至于round方法,他表示“四舍五入”,算法为Math.floor(x+0.5f),即将原来的数字加上0.5,之后再向下取整。所以,Math.round(11.5)的结果为12,Math.round(-11.5)的结果为-11。


八、下面代码有什么不妥之处?

1.if(username.equals(“zxx”)){}
2.int x=1; return x==1?true:false;

答:1.应该先判断username是否是null;如果是null,则会出现空指针异常。
        改为:if("zxx".equals(username)){}
      2.x==1本身就返回boolean型,再用三元操作符判断true和false多此一举。
        改为:return x==1;

九、请说出作用域public,private,protected以及不写时的区别?

作用域同类同包子类不同包
public
protected×
default××
private×××

public:接口访问权限
protected:继承访问权限
default:包访问权限
private:你无法访问(除了包含该成员的类以外,其他任何类都无法访问这个成员)


十、String、StringBuffer和StringBuilder的区别?

原文链接:https://www.jianshu.com/p/8c724dd28fa4

概念:用来处理字符串常用的类有3种:String、StringBuffer和StringBuilder

三者之间的区别:

  1. 都是final类,都不允许被继承;
  2. String类长度是不可变的,StringBuffer和StringBuilder类长度是可以改变的;
  3. StringBuffer类是线程安全的,StringBuilder不是线程安全的;

String 和 StringBuffer:
1、String类型和StringBuffer类型的主要性能区别:String是不可变的对象,因此每次在对String类进行改变的时候都会生成一个新的string对象,然后将指针指向新的string对象,所以经常要改变字符串长度的话不要使用string,因为每次生成对象都会对系统性能产生影响,特别是当内存中引用的对象多了以后,JVM的GC就会开始工作,性能就会降低;

2、使用StringBuffer类时,每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用,所以多数情况下推荐使用StringBuffer,特别是字符串对象经常要改变的情况;

3、在某些情况下,String对象的字符串拼接其实是被Java Compiler编译成了StringBuffer对象的拼接,所以这些时候String对象的速度并不会比StringBuffer对象慢,例如:

String s1 = “This is only a” + “ simple” + “ test”;

StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);

生成 String s1对象的速度并不比 StringBuffer慢。其实在Java Compiler里,自动做了如下转换:

Java Compiler直接把上述第一条语句编译为:

String s2 = “This is only a”;

String s3 = “ simple”;

String s4 = “ test”;

String s1 = s2 + s3 + s4;

这时候,Java Compiler会规规矩矩的按照原来的方式去做,String的concatenation(即+)操作利用了StringBuilder(或StringBuffer)的append方法实现,此时,对于上述情况,若s2,s3,s4采用String定义,拼接时需要额外创建一个StringBuffer(或StringBuilder),之后将StringBuffer转换为String;若采用StringBuffer(或StringBuilder),则不需额外创建StringBuffer

StringBuilder
StringBuilder是5.0新增的,此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比 StringBuffer 要快。两者的方法基本相同

使用策略
1、基本原则:如果要操作少量的数据,用String ;单线程操作大量数据,用StringBuilder ;多线程操作大量数据,用StringBuffer。
2、不要使用String类的”+”来进行频繁的拼接,因为那样的性能极差的,应该使用StringBuffer或StringBuilder类,这在Java的优化上是一条比较重要的原则,例如:

String result = "";
for (String s : hugeArray) {
result = result + s;
}
// 使用StringBuilder
StringBuilder sb = new StringBuilder();
for (String s : hugeArray) {
sb.append(s);
}

String result = sb.toString();

当出现上面的情况时,显然我们要采用第二种方法,因为第一种方法,每次循环都会创建一个String result用于保存结果,除此之外二者基本相同

3、 StringBuilder一般使用在方法内部来完成类似”+”功能,因为是线程不安全的,所以用完以后可以丢弃。StringBuffer主要用在全局变量中

4、相同情况下使用 StirngBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。而在现实的模块化编程中,负责某一模块的程序员不一定能清晰地判断该模块是否会放入多线程的环境中运行,因此:除非确定系统的瓶颈是在 StringBuffer 上,并且确定你的模块不会运行在多线程模式下,才可以采用StringBuilder;否则还是用StringBuffer。


十一、序列化是干什么的,有什么作用,什么情况下会用到?

参考来源:https://www.cnblogs.com/mkl34367803/p/10659776.html
1、系列化是干什么的?
序列化简单来说就保存对象在内存中的状态也可以说是实例化变量。这是Java提供的用来保存 Object state,一种保存对象状态的机制。只有实现了serializable接口的类的对象才能被实例化。

2、什么情况下会用到序列化?

 1、当你想把内存中的对象写入到硬盘时
 2、当你想用套接字在网络上传输对象时
 3、当你想通过RMI调用对象时
(RMI是什么东西?):RMI总结来说就是远程调用对象,在一个jvm上调用另一个jvm的对象。

3、序列化需要注意的事项

 1序列化只保存对象的状态,而不管对象的方法。
 2当一个父类实现了序列化,它的子类也自动实现序列化,不用显示进行实现了。
 3当一个实例对象引用其他对象,当序列化该对象时也把引用的对象进行了实例化。

个人总结:serializable接口就是Java提供用来进行高效率的异地共享实例对象的机制,实现这个接口即可。


十二、ArrayList和LinkedList有什么区别?

  1. ArrayList的实现是基于数组,LinkedList的实现是基于双向链表。
  2. 对于随机访问,ArrayList优于LinkedList,ArrayList可以根据下标以O(1)时间复杂度对元素进行随机访问。而LinkedList的每一个元素都依靠地址指针和它后一个元素连接在一起,在这种情况下,查找某个元素的时间复杂度是O(n)
  3. 对于插入和删除操作,LinkedList优于ArrayList,因为当元素被添加到LinkedList任意位置的时候,不需要像ArrayList那样重新计算大小或者是更新索引。
  4. LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个引用,一个指向前一个元素,一个指向后一个元素。

12、守护线程是什么?

Java线程分为用户线程和守护线程。

守护线程是程序运行的时候在后台提供一种通用服务的线程。所有用户线程停止,进程会停掉所有守护线程,退出程序。

Java中把线程设置为守护线程的方法:在 start 线程之前调用线程的 setDaemon(true) 方法。

注意:
setDaemon(true) 必须在 start() 之前设置,否则会抛出IllegalThreadStateException异常,该线程仍默认为用户线程,继续执行
守护线程创建的线程也是守护线程
守护线程不应该访问、写入持久化资源,如文件、数据库,因为它会在任何时间被停止,导致资源未释放、数据写入中断等问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值