关于java基础阶段面试常问到的几个问题
首先声明一下,本人只是一个java语言的初学者,这篇文章是我最近在北京面试java实习生岗位的时候经常遇到的关于java基础方面的一些问题,当然有可能我在编写的时候会穿插一些别的内容,只是自己在这里做一个类似于面试总结的一个东西,仅供大家参考,其中的一些问题答案大多是我参考了一些大佬们的见解,然后转用自己的语言描述出来的,如果大家发现有什么不对的地方,请留言指正,我会关注的,谢谢大家包含。
面向对象
简单聊一聊java面向对象的三大特性
封装:
经过查找资料和自己的理解,我认为封装就是把对象的属性和方法结合到一起,成为一个独立的个体,也就是把过程和数据包围起来,并且尽可能的隐藏里面的细节,只给外界提供一个接口,来让信任的类访问这些接口;这样可以提高代码的复用率,减少程序员对代码的重复书写,增强程序的可维护性;
继承:
我们发现多个类中有相同的方法和属性,我们把这些相同的属性和方法提取到一个新的类中,然后用关键词extends来让原来的类和新产生的类之间产生联系,这种联系称为继承;被继承的类叫做“父类/基类”,继承的类称为“子类/派生类”,子类实际上继承了父类所有的数据和方法,只是有些数据和方法是隐藏的,无法使用的,例如父类中用private修饰的方法和属性;
而且java中的继承是单继承的,一个类只能有一个父类,但是一个父类可以有多个子类;
多态:
多态就是同一种事物表现出多种形态,就向老话说的那样“龙生九子,子子不同”,在java种可以认为就是“同一个接口,有不同的实现方式”,而多态又分为编译时多态和运行时多态两种:
编译时多态:就是在编译过程种,同一个方法有不同的实现方式,举个最简单的例子,就像时同一个类中的无参构造和有参构造一样,也叫方法的重载,在创建对象的时候,如果你传了参数,就会执行有参构造,如果没有就会执行默认的无参构造,大家都知道两构造方法必须和类同名,这也就是同一个接口,多种实现方式
运行时多态:就是方法在执行的时候,才会去判断执行方法的业务,就像基于继承的方法的重写,当子类重写了父类中的某个方法的时候,当你调用这个方法时,他会去执行子类中重写的那个方法,而不是父类中的那个方法;还有在创建对象的时候,可以用父类声明,用子类实现;就像cat属于Animal,我们创建Animal的时候可以用cat来实现:Animal animal = new Cat;
集合
说一说list、set、map的区别
首先list和set是实现了collection接口的,而map本身就是一个接口;list里面存储的数据是有序的,可重复的;set里存储的数据是无序的,不可重复;而list个set存储的都是单列数据,而map存储的是key-value键值对类型的数据;
List:
list中接口中我们常用的是ArrayList、LinkedList和vector三种,其中vector是最早的一个集合类了,它和ArrayList的实现方式一样,唯一不同的是它底层运用了同步锁机制,是线程安全的;而ArrayList是线程不安全的,ArrayList是基于数组实现的,而且它不仅仅实现了list接口,还实现了可复制,可序列化和随机访问的接口,所以它在元素的查找方面相对比较快一些;
LinkedList底层是一个双向链表,而且它除了实现list接口,也是先了可复制,可序列化和队列的接口,因为是链表结构,所以在增删元素的性能上要比ArrayList要快一些,其也是线程不安全的;
Set
set也叫做无序集合,它中的元素是唯一的,也没有顺序,我们常用的有HashSet和TreeSet两种,这里我只介绍hashmap;hashset底层其实是hashmap的一个实例类来实现的,就像用add方法给set加数据,实际上是调用了map的put方法,而且存入hashset中的元素实际上是存储到了hashmap的key值上了,它是先调用hashcode方法来计算出元素的hash值,然后通过位运算得出值,来对应要存储的位置;那么我们都知道hashmap中是以key-value形式存储数据的,那么value是怎么来的,hashset会new一个标识性的Object对象,来充当value存储;
Map
map–映射,map中的数据也是无序的,而且一个key只能够映射一个value值,所以其中的key不可以重复,value值可以;我们常用的实现类有hashmap和hahstable两种
hashmap:
hashmap中可以存储null,其线程也是不安全的,他的初始容量是16,加载因子是0.75;他是这样存储数据的,他会用key的hash值%数组的长度 然后对应数组的下表来将数据存储到相应的链表位置上,当它扩容的时候,需要重新计算所有key的hash值重新存储,这样会有很大的耗能;
hashtable
hahstable出现的比较早,和vector一样,是属于比较老的存储容器了,他也是线程安全的,它的初始容量是11,加载因子也是0.75,存储方式和hashmap一样;
说一说线程有几种实现方式?
线程的实现方式一共有三种,分别是继承Thread类,实现Runnable接口,还有通过Callable和Future实现一个有返回值的线程;
Thread
例如一个A类继承了Thread类,就需要重写Run方法,就是该线程要执行的代码逻辑,启动线程是通过start方法;
Runnable
写一个类实现这个接口,一样要重写run方法,run方法一样是业务逻辑,但是这次启动线程是将实现类的对象作为参数,传入thread中,在调用start方法来实现的;
callable
和Runnable不一样,它提供了一个call方法来作为线程的执行体,call方法的功能要比run强大,它可以由返回值;
什么是死锁,什么是活锁?
死锁:
死锁就是两个或者两个以上的线程互相抢夺资源而造成的线程阻塞,如果没有外力影响下,会一直阻塞;产生死锁由四个条件:
1)当A线程占用了某个资源的时候,别的线程不能再使用该资源;
2)当A线程占用了该资源之后,别的线程不能再抢夺该资源;
3)当A线程请求某资源的时候,还占用这原有的资源;
4)循环等待,形成一个环形的占用资源;A线程占用B线程的资源,B线程占用C线程的资源,C线程占用A线程的资源,这样就是一个环形的资源占用;
活锁:
活锁就是一个线程的等待时间过长,但有可能被激活的现象;假如A线程占用资源,B线程再等待,再等待过程中C线程也来等待,然后资源释放之后先给C线程使用了,B线程接着等待,这就造成了一直等待,但是有可能被激活;
简单说说线程池
线程池是帮助我们管理线程,解决频繁创建和销毁线程而消耗资源的问题,我们常用有单一线程池,固定线程池,缓存线程池等;
线程池有CorePoolSize核心线程数,MaximumPoolSize最大线程数,keepAliveTime临时线程存活时间,WorkQueue保存任务的阻塞队列,TimeUnit临时线程存活时间的单位,Handler无法执行任务时候的处理器等参数;
它的执行过程是这样的:
1)当有新的任务来了之后,如果线程池中的线程数没有达到CorePoolSize数量,那么线程池就会启动一个新的线程来执行该任务,即使有空闲的线程也会新建的;
2)当达到CorePoolSize数量之后,会先把任务存储再阻塞队列中,当队列存储满了之后,假如你设置的最大线程数大于核心线程数,那么会启动临时线程数来执行这些任务;
3)假如启动的线程数达到最大线程数,那么将会把任务交割handler任务处理器去处理,拒绝接受任务了;
说说Synchronized同步锁和lock的区别
首先Synchronized是一个关键字,而lock是一个接口,Synchronized是在JVM层面上实现的,所以在释放锁的方面:Synchronized是执行完代码或者有异常的时候才会释放锁,lock是通过代码实现的,而lock必须得程序员手动finally方法中调用unlock方法来释放锁;获取锁的候,Synchronized没法自己获取锁,必须等待释放锁,而lock可以用trylock来尝试获取锁,如果锁在用,可以中断线程,去做别的事情;
数据库的一些概念
什么是DML,什么是DDL,什么是DCL?
DML:数据库操作语言,我们用的一些select、update、insert、delete就属于数据库操作语言;主要是对数据库中的数据进行操作;
DDL:数据库定义语言,我们使用的create、alter、drop等,可以改变表的结构,数据类型等,称为数据库的定义语言;
DCL:数据库控制语言,用来设置或者更改数据库用户权限的语句;
数据库中的主键和外键
首先主键和外键是为了保持数据的完整性和约束性;
主键:数据库中表的主键是能确定一条记录的唯一标识;一张表可以没有主键,但是主键不能为null,而且不能重复;
外键:主要用于和另外一张表的关联,外键可以是null,一张表也可以有多个外键。
数据库中索引
索引:索引是一种对数据库中的表的单列或者多列数据进行排序的一种存储结构,相当于一本数的目录一样;能够帮助快速查找到需要的数据;
唯一索引:就是所建立的索引值中不能有重复值,也就是索引中任意两行的值不能一样,就像如果为name这一列建立索引,那么就不能有两个同名的人;
主键索引:故名思意就是基于主键建立的索引,主键大家都知道是唯一的,不重复的,所以它可以认为是特殊的唯一索引;
聚集索引:就是建立的索引的数据顺序和表中存储的数据顺序一致,就被称为聚集索引;
数据库中的触发器
触发器是一中特殊类型的存储过程,当我们对数据库中的数据进行修改的时候,会触发一些触发器设定的效果,可以查询其他的表,他是自动的;例如我们修改某个部门的员工薪资,可以设置触发器在修改该员工的工资信息之后,自动触发修改该员工所在部门的平均工资;
这次就总结到这里,之后的基础问题我会持续更新,欢迎大佬指正批评;