==和equals的区别?
-
== 比较基本类型是比较值, 强类型是比较引用
-
基本类型只能用==, 没有equals方法
-
强类型的equals方法默认是继承自Object类的,该方法默认和==一样,比较引用。
如果重写后,按重写后的比较。
-
java规定如果重写equals方法,那么也推荐一并重写hashcode方法,保证对象相等的情况下,hashcode也要相等. (PS:hashcode相等不一定equals相等,因为会有hash冲突的情况)否则会造成使用HashMap,HashSet对象的时候出现错误。
String和StringBuilder,StringBuffer的区别 ?
-
String底层是不可变的类,所以每次赋值都会重新创建新的对象
所以如果要频繁的修改字符串的值,不推荐使用String。
应该使用StringBuffer或StringBuilder替代。
当考虑线程安全的情况下使用StringBuffer
不考虑线程安全的情况下使用StringBuilder效率更高
Static关键字的作用 ?
-
static可以修饰 内部类,静态导包,属性,方法
-
static修饰的属性和方法可以使用类名和对象访问,但是推荐使用类名访问,不论使用什么访问,都是访问的同一个内存空间,只有一份。
-
被static修饰的属性和方法属于类,不属于具体的对象。
所以static是共享的,建议在static属性上添加final只读,否则多处修改会造成数据安全的问题。
-
由于是类的属性和方法,所以存放在方法区中,除非卸载类,否则GC不予回收,所以不能够什么都去用static修饰方法。一般在工具类中的方法考虑添加static。
方法重载
-
构造器和实例方法和类方法都可以重载
-
重载是在本类中,要求:1. 方法名相同 2. 参数列表不同(个数,类型)
-
与其他方法签名部分无关
方法重写
-
重写是发生在子类和父类关系中的,子类重写/覆盖父类的方法
-
方法名相同
-
参数列表相同
-
访问修饰符要比父类的更宽泛(大),或者一样
-
返回值要一样或者是父类返回值的派生类
-
抛出的异常不可以比父类的更宽泛(大)
final的作用
-
final可以修饰类, 代表最终类,不可被继承
-
final可以修饰方法,代表最终方法, 不可被重写覆盖。故抽象方法不可以添加final
-
final可以修饰属性,代表常量,值不可变,需要区别的是:
-
基本类型: 值不可变
-
引用类型: 变量的引用值不可变,但其内部的属性是可以变的
-
异常的理解
-
java的异常的基类是Throwable,其下有两个子类,分为Exception(异常)和Error(错误)
-
Error代表错误,一般程序无法处理和修复
-
Exception代表异常,其下又会分为两大类异常。
-
检查性异常,一般称为checked异常,这类异常都继承自Exception类(RuntimeException除外)
-
非检查性异常,一般称为unchecked异常,这类异常都继承自RuntimeException
-
-
检查性异常要求程序必须显示处理的异常
-
非检查性异常系统不做要求,程序可自行选择是否添加处理代码
线性存储和链式存储的区别 ?
-
java中线性存储的数据结构有: 数组,ArrayList
它们的优点是:查找访问快.缺点是在非末尾的位置删除和插入效率低.
-
java中链式/表存储的数据结构有:LinkedList
它们的优点是:插入和删除效率高.缺点是访问非头尾的位置效率低.
常用数据结构的理解 ?
-
ArrayList和LinkedList实现自List接口,基类接口为Collection
-
HashSet和TreeSet实现自Set接口,基类接口为Collection
-
ArrayList和LinkedList有序,可重复
-
HashSet无序,不可重复
-
TreeSet排序(存放的排序数据需要实现Comparable接口),不可重复
HashMap底层实现原理 ?
-
HashMap底层是由数组+链表+红黑树实现
-
put 原理
-
根据key计算hash,找到要存储的数组位置
-
如果该位置为null,直接存储进去
-
如果不为null,判断key的equals是否相等,如果相等则覆盖并返回旧的值,
如果key不相等,那么会把新的数据以链表格式存储到该位置的末尾。
当该链表的长度超过8的时候,会转换成红黑树(因为链表的长度太长查找效率没有红黑树高效)。
-
-
get 原理
-
根据key计算hash,找到要获取数据的位置
-
判断该位置是否为null,为null返回null
-
不为null,循环链表或红黑树逐个判断equals是否相等,相等返回值,没找到
返回null。
-
-
扩容,默认hashmap底层大小为16, 扩容因子0.75,每次扩容2倍。
JVM内存模型(压轴落幕)
-
共享部分
-
堆(heap)
-
new出来的对象
-
-
方法区 / 元空间
-
常量池
-
静态属性
-
类的元数据
-
-
-
独享部分
-
栈 / 虚拟机栈 stack
-
局部变量表
-
操作数栈
-
静态链接 / 动态链接
-
方法出口
-
-
本地方法栈 stack 存放的都是native的方法,内部结构和虚拟机栈类似。
-
程序计数器
-
记录线程执行的位置
-
该位置是jvm中唯一不可能出现内存溢出或泄露的位置
-
-
位或 |,位与 &, 位异或 ^, 位非 ~ 运算符 **
-
这些运算都要把十进制转换为二进制
-
| 只有有1就为1, 否则就为0
-
& 两个数都为1就为1, 否则就为0
-
^ 两个数相同则为0, 不同则为1
-
~ 二进制取反, 0为1, 1为0。 以十进制为例: ~100=-101 -101=100
IO流
-
IO流分为 输入流InputStream和输出流OutputStream
-
输入流和输出流又分为 字节流和字符流
-
字符流的底层也为字节流
-
操作文件的时候使用字节流,操作字符的时候使用字符流
什么是缓冲区 ?
-
缓冲区分为输入缓冲区和输出缓冲区,
-
输入缓冲区:一次从磁盘中读取足够大的数据到缓冲区内存中
程序后续每次从缓冲区内存中读取一定量的数据,用于减少读取磁盘次数
-
输出缓冲区:每次把数据写到缓冲区内存中,当缓冲区内存数据量
达到一定量的时候,一次性写入磁盘,用于减少写入磁盘的次数
字节流和字符流转换
-
InputStreamReader
-
OutputStreamWriter
对象的创建有哪些方式
-
new(会执行构造器)
-
反序列化(Serializable不会执行构造,Externalizable会执行构造)
-
克隆(因为clone走的是本地native方法,所以是第三方平台库创建的对象,不会执行java的构造器)
-
反射(会执行构造器)
什么是序列化和反序列化 ?
-
序列化就是把程序内存中的数据持久化到介质(硬盘)上的过程
-
反序列化是把介质(硬盘)上的持久化数据,反向读取到程序内存中
-
序列化需要实现Serializable接口
-
反序列化会对应程序的版本号,如果修改过代码导致版本号不一致,无法反序列化,
会抛出InvalidClassException异常。
-
transient和static修饰的属性无法被序列化
什么是深拷贝和浅拷贝 ?
-
浅拷贝是把对象中的数据的值直接拷贝到克隆的对象中去,被克隆的对象中的属性如果是基本数据类型,那么无影响,如果有引用类型,那么拷贝到新的对象中也是这个引用.所有后续如果对引用类型修改,会有牵连。
-
深拷贝则是把对象中引用类型的属性再去克隆新的地址,这样克隆出来的两个对象的属性完全隔离。
类的加载过程?
-
类加载器会把二进制class文件加载到方法区
-
验证: 确保字节码内部信息完整,没有被篡改
-
准备: 初始化类的信息,在方法区中为static的属性分配空间和默认值
-
解析: 解析类中的元数据,属性,类,接口是否引用错误
-
初始化: 执行static代码块,赋初值。
-
使用
-
最后卸载,手动卸载和jvm结束自动卸载
类加载器
-
AppClassLoader 应用程序加载器,负责加载用户自定义的类
-
BootStrapClassLoader 启动类加载器,jvm启动的时候自动会调用底层平台的库,然后加载jre/lib中必备的jar。如我们常用的rt.jar。
-
ExtClassLoader 扩展类加载器,负责加载jre/lib/ext目录下的jar库。
-
这三个类加载器的关系为:
BootStrapClassLoader > ExtClassLoader > AppClassLoader
什么是双亲委派机制 ?
-
当某个类加载器需要加载某个
.class
文件时,它首先把这个任务委托给他的上级类加载器,递归这个操作,如果上级的类加载器没有加载,自己才会去加载这个类。 -
防止重复加载同一个
.class
。通过委托去向上面问一问,加载过了,就不用再加载一遍。 -
保证核心
.class
不能被篡改,保证数据安全。
程序,进程,线程的关系 ?
-
一个程序可以包含多个进程
-
一个进程可以包含多个线程
-
线程是程序执行的最小单元
多线程创建方式
-
继承Thread类
-
实现Runnable接口
-
实现Callable接口
-
线程池
多线程安全问题怎么解决?
-
多实例,缺点: 浪费空间
-
添加synchronize关键字,缺点: 效率低,逐个线程排队执行
-
使用本地线程ThreadLocal
-
使用Lock锁,缺点: 效率低,逐个线程排队执行
-
使用局部变量,因为局部变量不存在线程安全的问题。
缺点是:多线程的时候不一定具备这种场景
volatile关键字的作用,能保证线程安全吗 ?
-
保证线程获取的数据是最新值
-
防止指令的重排序
-
无法保证线程的安全性
线程的状态
-
新建
-
就绪
-
运行
-
等待 / 阻塞
-
死亡
你知道哪些锁
-
可重入锁和不可重入锁
-
可重入锁可能导致死锁
-
死锁有四大条件
-
互斥、占用且等待新资源、不可抢占、循环等待
-
解决死锁打破四个条件之一即可
-
比如我常用的方式是如果有可重入锁的情况,尽量保证多个位置按相同锁的顺序加锁
-
-
排它锁
-
获取到排它锁后,其他线程无法获取共享锁读取数据也无法获取排它锁写入数据
-
-
共享锁
-
获取到共享锁后,其他线程可以再次获取共享锁同时读取数据,但不可以获取排它锁进行修改数据
-
sleep和yield和wait区别
-
sleep和yield都属于Thread类的静态本地方法
-
sleep和yield都不会释放对象锁
-
sleep是等待固定时间后进入就绪态
-
yield是直接从运行退让到就绪态(给其他线程空出机会)
-
wait是Object的方法
-
wait是进入等待状态,并且释放当前线程占用的对象锁(synchronized)
interrupt和stop的区别 ?
-
使用stop或者interrupt 不推荐stop,因为强制停止,会造成线程方法直接中断,导致不可预期后果
-
interrupt打断一个线程,不会直接强制停止我们的线程,
而是给一个标志, 线程方法中可以判断isInterrupted这个标志,然后自行结束线程.
-
interrupt如果打断的是一个等待状态的线程,那么会收到一个
InterruptException异常,并且标志会被重置。
什么是反射 ?
-
Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法
-
对于通用性的模块和功能,首先考虑使用反射。
TCP和UDP的区别
-
TCP需要三次握手,面向连接,可靠机制保证数据不丢失且有序,但是效率不高
-
UDP不可靠,无连接,适用于实时性较高,但对安全性较低的地方。
Finalize方法 ?
-
Object的空方法,GC要回收哪个对象,就会提前调用哪个对象的该方法
-
该方法代表GC回收对象时,如果被回收的对象重写了该方法,那么回收该对象之前会先调用该方法(仅会调用一次)
垃圾回收区域
-
首先程序员无法具体控制GC何时执行回收
-
GC是Java的守护线程在后台运行,一般分为轻GC(majorGC)和重GC(fullGC)
-
GC90%以上情况都是回收堆里面的新生代对象
-
当对象的年龄达到15(默认值,可以jvm参数修改),进入老年代。
-
老年代内存如果快满了,会执行fullGC。
-
堆中会划分为新生代-(内含Eden区,Survivor-from区和Survivor-to区,这2个区会来回互换,腾出一个给到下次回收使用,具体参考复制算法),老年代(老年代的对象都是年龄较大或比较大的对象)
GC算法
-
GC算法有: 引用计数法,可达性分析算法,标记清除,标记整理,复制,分代收集
-
Java主流虚拟机都是通过可达性分析算法确定一个对象是否为垃圾对象
-
标记清除:造成内存碎片过多,不适合后续使用
-
复制算法:缺点是空间使用率低,因为要空出一半做复制。优点是效率高,不会有内存碎片
-
标记整理算法:优点是不会产生空间碎片,但是效率相对较低。
-
分代收集算法:在不同的区域使用不同的回收算法,如
-
新生代一般采用复制算法,比如幸存者0区和1区的复制
-
老年代一般采用标记整理算法,所以效率比较低,重GC会停止其他业务线程的使用
-
什么是强引用,软引用,弱引用,虚引用 ?
强引用 User user = new User()
软引用SoftReference<User> user = new SoftReference<>(new User());
弱引用WeakReference<User> user = new WeakReference<>(new User());
虚引用 PhantomReference
五大原则是哪些
-
单一职责 一个接口、类、方法只负责一件事情
-
开闭原则 对修改关闭,对扩展开放
-
里氏替换原则 子类可以替换父类, 父类可以接收子类对象, 实现多态(尽量使用父类/接口去new子类)
-
依赖倒置 面向接口编程,关注抽象,不关注细节实现
-
接口隔离 拒绝胖子接口,接口多个方法隔离到不同的接口中
静态代理和动态代理
-
静态代理的缺点是只能针对具体的业务进行代理,无法通用
-
动态代理有JDK方式和CGLIB方式
-
默认推荐使用JDK方式,该方式要求被代理的类要有接口
-
CGLIB需要第三方jar包的依赖,可以不要求被代理对象有接口
-
代理可以使业务功能增强
JDBC执行流程?
-
加载驱动
Class.forName("驱动路径")
-
建立连接
DriverManager.getConnection(url,username,password)
-
创建普通指令
CreateStatement()
或者预编译指令PrepareStatement(Sql)
-
执行sql语句,调用
executeQuery
或executeUpdate
-
最重要的一步,释放与数据库连接的资源. 关闭结果集,关闭指令,关闭连接
rs.close(), statement.close(), connection.close()
Statement和PreparedStatement的区别?怎么防止SQL注入?
-
PreparedStatement是Statement的子接口,都为执行SQL指令的接口标准
-
Statement执行的SQL语句有被SQL注入的风险。
-
PreparedStatement是预编译,即先编译语句和占位符,执行阶段在加入数据,可以预防SQL注入。
-
同时由于PreparedStatement是预编译,Statement是执行层面先编译再执行,所以在多次执行同一SQL的情况下,PreparedStatement具有更高的效率。
----------------------------------------------------数据库分割线-------------------------------------------
什么是SQL ?
-
结构化查询语言
-
SQL又包含DDL(数据定义语言),DCL(数据控制语言),DQL(数据查询语言),DML(数据操纵语言),TCL(事务控制语言)
-
DDL:负责创建CREATE或修改ALTER或删除DROP数据库对象的,对象有 表,存储过程,函数等等
-
DCL:负责创建或修改或删除数据库用户和角色权限的,控制对象是否有权限访问的
-
DQL:负责查询数据库表和视图的
-
DML:负责添加,删除,修改数据的
-
TCL:负责事务的,如commit,rollback
char、nchar、varchar、nvarchar区别
-
char定长,varchar变长,确定大小的使用char效率更高,不确定大小的字段使用varchar
-
nchar和nvarchar按字符Unicode编码存储,char和varchar按字节存储。
drop,delete,truncate的区别
-
drop,truncate属于DDL。 delete属于DML语句。
-
drop是删除表的结构定义,所以连带数据一起删掉了。delete和truncate只会删除数据,而不会删除定义。
-
delete可以跟条件删除,truncate不能跟条件。
-
delete删除速度慢,因为要记录日志。truncate属于截断表,会连带日志和数据一起删除,所以删除速度极快。
数据库三范式
-
第一范式1NF:分割不同的字段到确保不可再分.
-
第二范式2NF:确保每一条数据的唯一性。
-
第三范式3NF:当前表不要去保存关系表非主关键字以外的其他字段数据。
3NF避免了数据的冗余性,保证数据的完整性,节省了空间。
3NF不一定要求必须遵循,数据量体量特别大的地方不要求满足第三范式,以提高查询的效率。
表连接
-
内连接inner join,显示两个表匹配条件的数据,不匹配的不显示
-
左外连接left [outer] join,左边主表的数据必定全部显示,被连接的次表如果匹配则显示,不匹配显示为null
-
右外连接right [outer] join,右边表的数据必定全部显示,左边表如果匹配则显示,不匹配显示为null
-
全连接,两个表匹配的数据会显示,如果不匹配的则各自行的匹配字段显示为null(MySql没有全连接)
-
交叉连接cross join,不添加匹配条件,形成笛卡尔积,即A表每条数据和B表每条数据各自匹配一次,如A5条数据B4条数据 结果为20条数据。
-
自然连接natural join,无需on条件,两张表中寻找那些数据类型和列名都相同的字段,然后自动地将他们连接起来,并返回匹配结果。
mysql存储引擎有哪些,区别是什么?
-
mysql主流的存储引擎有innoDB,myisam,memory.
-
默认使用的是innoDB.
-
innoDB和myisam的共同点都支持b+ tree索引。
-
innoDB和myisam有很多区别,最大的区别有两个
-
innoDB支持事务,而myisam不支持
-
innoDB的数据由frm和ibd存储,数据和索引都在ibd中。myisam的数据由frm,myi,myd三个文件存储,数据存储在myd中,索引存储在myi中。
-
其他区别:innoDB支持行锁和表锁,myisam只支持表锁
-
innoDB支持外键, myisam不支持外键
-
innoDB支持自动增长auto increment, myisam不支持
-
innoDB查询较低于myisam,修改高优于myisam。
-
Innodb使用的是聚簇索引,MyISam使用的是非聚簇索引
-
PS:聚簇索引是建立在一个表中的主键或唯一键或rowid(只有在没有为表分配主键和唯一键才关联rowid)上,其作用是用户查询辅助索引的时候,可以通过key快速定位到聚簇索引再通过聚簇索引的主键索引找到数据。
-
union和union all区别 ?
-
union是将两个表的结果集合并,并且去重,要求列的数量相等。(Oracle会自动排序,且列的类型要兼容)
-
union all是将两个表的结果集直接合并,不会去重。
谈谈对索引的理解?怎么提升查询效率?有一个表数据量查询很慢,怎么解决?
-
索引的作用是大大的提升查询的效率,但是会增加数据修改和录入的时间。
-
常用的索引有唯一索引,普通索引,联合索引。其他还有全文索引(不推荐)
-
唯一索引必须创建在唯一键或主键上。
-
innodb下每个表都会有一个聚簇索引,该索引用来提升整行的查询效率。
聚簇索引默认建立在唯一键或主键上,如果表没有创建唯一键或主键,那么聚簇索引会建立在mysql自带的rowid上。
-
可以通过explain分析sql语句,确定索引执行的情况,来优化SQL。
事务是什么
数据库的为了保证数据操作的完整性和一致性,提供了事务的功能。
事务有四个特性来保证数据的安全,分别为ACID
-
原子性:把整个流程当做一个原子来执行,要么都成功,要么都失败
-
一致性:事务的执行前,和执行后,数据是一致的
-
隔离性: 多个事务之间是互相隔离独立的,互不影响的
-
持久性:事务执行完成后,对数据的操作的永久保存的
MySql中的锁
-
行锁 锁住选中的行
-
表锁 全表
-
排它锁 for update,添加排它锁,排它锁不允许其他事务在该数据上 再次添加共享锁和排它锁,也不允许修改。
-
共享锁 lock in share mode,添加共享锁,共享锁允许其他事务在该 数据上再次添加共享锁,但不允许添加排它锁,也不允许修改。
脏读、不可重复读、幻读
-
脏读:A事务在修改数据,但是没有提交/回滚,此时B事务查询到了A事务修改的数据,那么这个数据就是脏数据。
事务隔离级别为read committed时,可以预防该问题。
-
不可重复读:A事务在当前事务中前后重复读取多次数据,返回的结果不一致,因为中途有其他B事务修改了该数据,这种情况称为不可重复读。
事务隔离级别为repeatable read时,可以预防该问题。
-
幻读:A事务在当前事务中前后重复读取多次数据,中途有其他事务在表中做了插入或删除数据,导致前后读取的数据【数量】不一致,就像发生了幻觉一样。
mysql的innoDB引擎事务隔离级别为repeatable read时,可以预防该问题,其他引擎和Oracle需要调整到串行化Serializable级别才能预防该问题。
数据库的隔离级别有哪些?spring有哪些隔级别
-
Spring有五种,多出来的一种是default,意思是spring不参与设置隔离级别,而是用数据库默认的级别。
-
Mysql默认使用的是可重复。
-
Oracle默认使用的是读已提交。
---------------------------------------web编程分割线-----------------------------------------------------
Tomcat目录结构说说
-
bin 存储的是启动和停止等可执行文件或脚本
-
conf 存储的server.xml、context.xml等配置文件,修改端口或连接池信息可以在这里
-
lib 存储tomcat运行所需jar包的地方,也可以自行为tomcat添加其他jar包放这里
-
logs 存储tomcat运行的一些日志信息的目录
-
temp 临时目录,运行生成一些临时文件
-
webapps 项目执行的地方,把要运行的项目放在这里面
-
work 工作目录,编译后的jsp文件,会在这里
Servlet的生命周期
-
默认在第一次访问的时候,由容器创建Servlet对象,
并执行init方法。
如果设置了loadOnStartup为大于等于0的数,那么在容器启动的时候,servlet会按此值升序加载并执行init方法。
注意:后续不会再次创建Servlet实例,Servlet是单实例的。
-
然后每次请求的时候执行service业务方法,HTTPServlet中对service方法已经重写,会根据用户的请求方式分别调用对应的doGet/doPost/doPut/doDelete等方法。
-
容器关闭时,会调用destroy方法。
JSP执行原理
-
java server page Java服务器页面,本质上就是一个Servlet
-
jsp首次执行的时候会将JSP翻译为servlet文件,后续执行不会再次翻译
-
然后编译并且执行该servlet的service方法
-
执行完成后,会用response响应输出html的静态代码
JSP包含哪些内容 ?
-
指令<%@ %>
-
声明<%! %>
-
表达式<%= %>
-
小脚本<% %>
-
注释<%-- --%>
-
静态内容HTML
转发和重定向的区别 ?
-
转发地址栏不会变。重定向地址栏会改变
-
转发是服务器转发,只能转发内部资源,属于一次请求。重定向是二次请求,可以跳转外部链接。
-
转发由于地址栏不变,所以刷新会重复提交之前的表单数据。重定向是刷新跳转之后的地址。
GET和POST的区别
-
get是明文提交,所以对敏感的数据要注意安全性的问题。
-
post是密文提交,地址栏不可见。
-
get提交一般用于获取数据。post一般用于修改数据。
-
get由于是地址栏明文显示,那么地址栏对数据的长度有限制。而post理论上没有限制。
-
get会被浏览器主动cache,post不会
-
get只接收ASCII字符,而post没有限制。
JSP的四个作用域
-
pageContext 当前页面有效
-
request 一次请求中有效
-
session 一次会话中有效
-
application 一次应用中所有用户有效
JSP的九大内置对象
-
所谓内置对象,就是容器自动创建好给我们用的,不用我们创建。
-
out 用于输出内容到客户端
-
page 代表当前页面 类似servlet中的this
-
pageContext 页面上下文
-
config 配置信息对象
-
request 请求对象
-
response 响应对象
-
session 会话对象
-
application 应用对象
-
exception 异常对象